diff --git a/DEPS b/DEPS
index 5fcc2083..8ac1273 100644
--- a/DEPS
+++ b/DEPS
@@ -145,7 +145,7 @@
   # 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': 'df54f37a5dc137258b3ce375d72d1ade8792b999',
+  'skia_revision': '170d9905cc7c4351260b4cd1b78ae1bbee3e02a5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -157,7 +157,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '125154257bc2453998a360555f53939e48de4ebd',
+  'angle_revision': '265fdf0c5fd6b1e28a54c18ca40a8461c7f449a7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # 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 PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'a7318ae4c6b0f81a742a9fdcda1c2c1fd01c9107',
+  'pdfium_revision': '185f7a3a8104c27c49797979fa8f25bf3dff511d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -228,7 +228,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
-  'android_sdk_build-tools_version': 'DLK621q5_Bga5EsOr7cp6bHWWxFKx6UHLu_Ix_m3AckC',
+  'android_sdk_build-tools_version': '5DL7LQQjVMLClXLzLgmGysccPGsGcjJdvH9z5-uetiIC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_emulator_version
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '0b2599c8929ee01bb7d7f0dc77cd81c08c796b40',
+  'dawn_revision': '786f76574a7face893b369e0dcca60b7bc9fd1a8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -484,7 +484,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '2ed6691f28486c8b168f62ccb20745e9db4c4afb',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '7c66ab5c14457a65db886d6450f23943e7d24711',
       'condition': 'checkout_ios',
   },
 
@@ -789,6 +789,17 @@
       'dep_type': 'cipd',
   },
 
+  'src/third_party/byte_buddy/android_sdk_build_tools_25_0_2': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_sdk/public/build-tools',
+              'version': 'kwIs2vdfTm93yEP8LG5aSnchN4BVEdVxbqQtF4XpPdkC',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
   'src/third_party/catapult':
     Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
 
@@ -814,7 +825,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '1e33334b48b1f7fe0605cb843a389be6a633066f',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '209c6a42eac6330f48bb450defbcfc1762c6a1d6',
       'condition': 'checkout_linux',
   },
 
@@ -839,7 +850,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9f4b37db0e36216cdb09dadc07e200ca25c14ea6',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '72fbaf4d465e86222c92a21283a0d7406ca05323',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1078,7 +1089,7 @@
   },
 
   'src/third_party/libjpeg_turbo':
-    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'cd241207cb905ff768837208e84bd0808835089d',
+    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'd460d6b1cb965c3363f36f7ed716f13d60cdb65d',
 
   'src/third_party/liblouis/src': {
       'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '97ce1c67fccbd3668291b7e63c06161c095d49f2',
@@ -1380,7 +1391,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'a1351271e6cfedecd9d16258a21b2cf097ea2242',
+    Var('webrtc_git') + '/src.git' + '@' + 'f5e5d250bc85616e74487f8330ed8d99cc9cf84f',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1421,7 +1432,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2ab018e61faa8a4665948780567df5c8cb887f2d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fad9a43018a3e1dfbab4e250a4e2af8ac9662ffe',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 807d726..5931c0d 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -147,14 +147,8 @@
   return pref_store_path;
 }
 
-// static
 base::FilePath AwBrowserContext::GetCookieStorePath() {
-  FilePath cookie_store_path;
-  if (!base::PathService::Get(base::DIR_ANDROID_APP_DATA, &cookie_store_path)) {
-    NOTREACHED() << "Failed to get app data directory for Android WebView";
-  }
-  cookie_store_path = cookie_store_path.Append(FILE_PATH_LITERAL("Cookies"));
-  return cookie_store_path;
+  return GetCookieManager()->GetCookieStorePath();
 }
 
 // static
@@ -278,6 +272,11 @@
   return autocomplete_history_manager_.get();
 }
 
+CookieManager* AwBrowserContext::GetCookieManager() {
+  // TODO(amalova): create cookie manager for non-default profile
+  return CookieManager::GetInstance();
+}
+
 base::FilePath AwBrowserContext::GetPath() {
   return context_storage_path_;
 }
@@ -403,7 +402,7 @@
   context_params->cookie_manager_params =
       network::mojom::CookieManagerParams::New();
   context_params->cookie_manager_params->allow_file_scheme_cookies =
-      CookieManager::GetInstance()->AllowFileSchemeCookies();
+      GetCookieManager()->AllowFileSchemeCookies();
 
   context_params->initial_ssl_config = network::mojom::SSLConfig::New();
   // Allow SHA-1 to be used for locally-installed trust anchors, as WebView
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 3dcb225..29e791d 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -62,7 +62,7 @@
 
   base::FilePath GetCacheDir();
   base::FilePath GetPrefStorePath();
-  static base::FilePath GetCookieStorePath();
+  base::FilePath GetCookieStorePath();
   static base::FilePath GetContextStoragePath();
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
@@ -78,6 +78,7 @@
 
   AwFormDatabaseService* GetFormDatabaseService();
   autofill::AutocompleteHistoryManager* GetAutocompleteHistoryManager();
+  CookieManager* GetCookieManager();
 
   // TODO(amalova): implement for non-default browser context
   bool IsDefaultBrowserContext() { return true; }
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index de2480e6..593e0377 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -218,6 +218,7 @@
     content::RenderFrameHost* render_frame_host) {}
 
 void PassMojoCookieManagerToAwCookieManager(
+    CookieManager* cookie_manager,
     const network::mojom::NetworkContextPtr& network_context) {
   // Get the CookieManager from the NetworkContext.
   network::mojom::CookieManagerPtrInfo cookie_manager_info;
@@ -225,8 +226,7 @@
 
   // Pass the CookieManagerPtrInfo to android_webview::CookieManager, so it can
   // implement its APIs with this mojo CookieManager.
-  CookieManager::GetInstance()->SetMojoCookieManager(
-      std::move(cookie_manager_info));
+  cookie_manager->SetMojoCookieManager(std::move(cookie_manager_info));
 }
 
 #if BUILDFLAG(ENABLE_MOJO_CDM)
@@ -360,7 +360,8 @@
 
   // Pass a CookieManager to the code supporting AwCookieManager.java (i.e., the
   // Cookies APIs).
-  PassMojoCookieManagerToAwCookieManager(network_context);
+  PassMojoCookieManagerToAwCookieManager(aw_context->GetCookieManager(),
+                                         network_context);
 
   return network_context;
 }
diff --git a/android_webview/browser/cookie_manager.cc b/android_webview/browser/cookie_manager.cc
index cc12b05..24da8b0b 100644
--- a/android_webview/browser/cookie_manager.cc
+++ b/android_webview/browser/cookie_manager.cc
@@ -19,6 +19,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/containers/circular_deque.h"
+#include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -161,6 +162,17 @@
   return g_lazy_instance.Pointer();
 }
 
+namespace {
+base::FilePath GetPathInAppDirectory(std::string path) {
+  base::FilePath result;
+  if (!base::PathService::Get(base::DIR_ANDROID_APP_DATA, &result)) {
+    NOTREACHED() << "Failed to get app data directory for Android WebView";
+  }
+  result = result.Append(FILE_PATH_LITERAL(path));
+  return result;
+}
+}  // namespace
+
 CookieManager::CookieManager()
     : accept_file_scheme_cookies_(kDefaultFileSchemeAllowed),
       cookie_store_created_(false),
@@ -170,10 +182,23 @@
   cookie_store_client_thread_.Start();
   cookie_store_backend_thread_.Start();
   cookie_store_task_runner_ = cookie_store_client_thread_.task_runner();
+
+  // TODO(amalova): initialize cookie_store_path_ for non-default profile
+  // Do not migrate cookies for non-default profile.
+  cookie_store_path_ = GetPathInAppDirectory("Default/Cookies");
+  MigrateCookieStorePath();
 }
 
 CookieManager::~CookieManager() {}
 
+void CookieManager::MigrateCookieStorePath() {
+  base::FilePath old_cookie_store_path = GetPathInAppDirectory("Cookies");
+
+  if (base::PathExists(old_cookie_store_path)) {
+    base::Move(old_cookie_store_path, cookie_store_path_);
+  }
+}
+
 // Executes the |task| on |cookie_store_task_runner_| and waits for it to
 // complete before returning.
 //
@@ -253,13 +278,16 @@
   }
 }
 
+base::FilePath CookieManager::GetCookieStorePath() {
+  return cookie_store_path_;
+}
+
 net::CookieStore* CookieManager::GetCookieStore() {
   DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
 
   if (!cookie_store_) {
     content::CookieStoreConfig cookie_config(
-        AwBrowserContext::GetCookieStorePath(),
-        true /* restore_old_session_cookies */,
+        cookie_store_path_, true /* restore_old_session_cookies */,
         true /* persist_session_cookies */, nullptr /* storage_policy */);
     cookie_config.client_task_runner = cookie_store_task_runner_;
     cookie_config.background_task_runner =
@@ -332,24 +360,42 @@
   RunPendingCookieTasks();
 }
 
-void CookieManager::SetShouldAcceptCookies(bool accept) {
+void CookieManager::SetShouldAcceptCookies(JNIEnv* env,
+                                           const JavaParamRef<jobject>& obj,
+                                           jboolean accept) {
   AwCookieAccessPolicy::GetInstance()->SetShouldAcceptCookies(accept);
 }
 
-bool CookieManager::GetShouldAcceptCookies() {
+jboolean CookieManager::GetShouldAcceptCookies(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   return AwCookieAccessPolicy::GetInstance()->GetShouldAcceptCookies();
 }
 
-void CookieManager::SetCookie(const GURL& host,
-                              const std::string& cookie_value,
-                              base::OnceCallback<void(bool)> callback) {
+void CookieManager::SetCookie(JNIEnv* env,
+                              const JavaParamRef<jobject>& obj,
+                              const JavaParamRef<jstring>& url,
+                              const JavaParamRef<jstring>& value,
+                              const JavaParamRef<jobject>& java_callback) {
+  DCHECK(java_callback) << "Unexpected null Java callback";
+  GURL host(ConvertJavaStringToUTF16(env, url));
+  std::string cookie_value(ConvertJavaStringToUTF8(env, value));
+  base::OnceCallback<void(bool)> callback =
+      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
+                     ScopedJavaGlobalRef<jobject>(java_callback));
+
   ExecCookieTask(base::BindOnce(&CookieManager::SetCookieHelper,
                                 base::Unretained(this), host, cookie_value,
                                 std::move(callback)));
 }
 
-void CookieManager::SetCookieSync(const GURL& host,
-                                  const std::string& cookie_value) {
+void CookieManager::SetCookieSync(JNIEnv* env,
+                                  const JavaParamRef<jobject>& obj,
+                                  const JavaParamRef<jstring>& url,
+                                  const JavaParamRef<jstring>& value) {
+  GURL host(ConvertJavaStringToUTF16(env, url));
+  std::string cookie_value(ConvertJavaStringToUTF8(env, value));
+
   ExecCookieTaskSync(base::BindOnce(&CookieManager::SetCookieHelper,
                                     base::Unretained(this), host,
                                     cookie_value));
@@ -393,12 +439,19 @@
   }
 }
 
-std::string CookieManager::GetCookie(const GURL& host) {
+ScopedJavaLocalRef<jstring> CookieManager::GetCookie(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jstring>& url) {
+  GURL host(ConvertJavaStringToUTF16(env, url));
+
   net::CookieList cookie_list;
   ExecCookieTaskSync(base::BindOnce(&CookieManager::GetCookieListAsyncHelper,
                                     base::Unretained(this), host,
                                     &cookie_list));
-  return net::CanonicalCookie::BuildCookieLine(cookie_list);
+
+  return base::android::ConvertUTF8ToJavaString(
+      env, net::CanonicalCookie::BuildCookieLine(cookie_list));
 }
 
 void CookieManager::GetCookieListAsyncHelper(const GURL& host,
@@ -432,12 +485,20 @@
 }
 
 void CookieManager::RemoveSessionCookies(
-    base::OnceCallback<void(bool)> callback) {
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& java_callback) {
+  DCHECK(java_callback) << "Unexpected null Java callback";
+  base::OnceCallback<void(bool)> callback =
+      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
+                     ScopedJavaGlobalRef<jobject>(java_callback));
+
   ExecCookieTask(base::BindOnce(&CookieManager::RemoveSessionCookiesHelper,
                                 base::Unretained(this), std::move(callback)));
 }
 
-void CookieManager::RemoveSessionCookiesSync() {
+void CookieManager::RemoveSessionCookiesSync(JNIEnv* env,
+                                             const JavaParamRef<jobject>& obj) {
   ExecCookieTaskSync(base::BindOnce(&CookieManager::RemoveSessionCookiesHelper,
                                     base::Unretained(this)));
 }
@@ -465,12 +526,22 @@
   std::move(callback).Run(num_deleted > 0u);
 }
 
-void CookieManager::RemoveAllCookies(base::OnceCallback<void(bool)> callback) {
+void CookieManager::RemoveAllCookies(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& java_callback) {
+  DCHECK(java_callback) << "Unexpected null Java callback";
+
+  base::OnceCallback<void(bool)> callback =
+      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
+                     ScopedJavaGlobalRef<jobject>(java_callback));
+
   ExecCookieTask(base::BindOnce(&CookieManager::RemoveAllCookiesHelper,
                                 base::Unretained(this), std::move(callback)));
 }
 
-void CookieManager::RemoveAllCookiesSync() {
+void CookieManager::RemoveAllCookiesSync(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj) {
   ExecCookieTaskSync(base::BindOnce(&CookieManager::RemoveAllCookiesHelper,
                                     base::Unretained(this)));
 }
@@ -491,12 +562,14 @@
   }
 }
 
-void CookieManager::RemoveExpiredCookies() {
+void CookieManager::RemoveExpiredCookies(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj) {
   // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
-  HasCookies();
+  HasCookies(env, obj);
 }
 
-void CookieManager::FlushCookieStore() {
+void CookieManager::FlushCookieStore(JNIEnv* env,
+                                     const JavaParamRef<jobject>& obj) {
   ExecCookieTaskSync(base::BindOnce(&CookieManager::FlushCookieStoreAsyncHelper,
                                     base::Unretained(this)));
 }
@@ -509,7 +582,8 @@
   }
 }
 
-bool CookieManager::HasCookies() {
+jboolean CookieManager::HasCookies(JNIEnv* env,
+                                   const JavaParamRef<jobject>& obj) {
   bool has_cookies;
   ExecCookieTaskSync(base::BindOnce(&CookieManager::HasCookiesAsyncHelper,
                                     base::Unretained(this), &has_cookies));
@@ -552,7 +626,15 @@
   return accept_file_scheme_cookies_;
 }
 
-void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
+jboolean CookieManager::AllowFileSchemeCookies(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return AllowFileSchemeCookies();
+}
+
+void CookieManager::SetAcceptFileSchemeCookies(JNIEnv* env,
+                                               const JavaParamRef<jobject>& obj,
+                                               jboolean accept) {
   base::AutoLock lock(accept_file_scheme_cookies_lock_);
   bool success;
   ExecCookieTaskSync(
@@ -591,116 +673,8 @@
   std::move(complete).Run();
 }
 
-static void JNI_AwCookieManager_SetShouldAcceptCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    jboolean accept) {
-  CookieManager::GetInstance()->SetShouldAcceptCookies(accept);
-}
-
-static jboolean JNI_AwCookieManager_GetShouldAcceptCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return CookieManager::GetInstance()->GetShouldAcceptCookies();
-}
-
-static void JNI_AwCookieManager_SetCookie(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& url,
-    const JavaParamRef<jstring>& value,
-    const JavaParamRef<jobject>& java_callback) {
-  DCHECK(java_callback) << "Unexpected null Java callback";
-  GURL host(ConvertJavaStringToUTF16(env, url));
-  std::string cookie_value(ConvertJavaStringToUTF8(env, value));
-  CookieManager::GetInstance()->SetCookie(
-      host, cookie_value,
-      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
-                     ScopedJavaGlobalRef<jobject>(java_callback)));
-}
-
-static void JNI_AwCookieManager_SetCookieSync(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& url,
-    const JavaParamRef<jstring>& value) {
-  GURL host(ConvertJavaStringToUTF16(env, url));
-  std::string cookie_value(ConvertJavaStringToUTF8(env, value));
-
-  CookieManager::GetInstance()->SetCookieSync(host, cookie_value);
-}
-
-static ScopedJavaLocalRef<jstring> JNI_AwCookieManager_GetCookie(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& url) {
-  GURL host(ConvertJavaStringToUTF16(env, url));
-
-  return base::android::ConvertUTF8ToJavaString(
-      env, CookieManager::GetInstance()->GetCookie(host));
-}
-
-static void JNI_AwCookieManager_RemoveSessionCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jobject>& java_callback) {
-  DCHECK(java_callback) << "Unexpected null Java callback";
-  CookieManager::GetInstance()->RemoveSessionCookies(
-      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
-                     ScopedJavaGlobalRef<jobject>(java_callback)));
-}
-
-static void JNI_AwCookieManager_RemoveSessionCookiesSync(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  CookieManager::GetInstance()->RemoveSessionCookiesSync();
-}
-
-static void JNI_AwCookieManager_RemoveAllCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jobject>& java_callback) {
-  DCHECK(java_callback) << "Unexpected null Java callback";
-  CookieManager::GetInstance()->RemoveAllCookies(
-      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
-                     ScopedJavaGlobalRef<jobject>(java_callback)));
-}
-
-static void JNI_AwCookieManager_RemoveAllCookiesSync(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  CookieManager::GetInstance()->RemoveAllCookiesSync();
-}
-
-static void JNI_AwCookieManager_RemoveExpiredCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  CookieManager::GetInstance()->RemoveExpiredCookies();
-}
-
-static void JNI_AwCookieManager_FlushCookieStore(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  CookieManager::GetInstance()->FlushCookieStore();
-}
-
-static jboolean JNI_AwCookieManager_HasCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return CookieManager::GetInstance()->HasCookies();
-}
-
-static jboolean JNI_AwCookieManager_AllowFileSchemeCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return CookieManager::GetInstance()->AllowFileSchemeCookies();
-}
-
-static void JNI_AwCookieManager_SetAcceptFileSchemeCookies(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    jboolean accept) {
-  return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
+static jlong JNI_AwCookieManager_GetDefaultCookieManager(JNIEnv* env) {
+  return reinterpret_cast<intptr_t>(CookieManager::GetInstance());
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/cookie_manager.h b/android_webview/browser/cookie_manager.h
index 88e57910..26428846 100644
--- a/android_webview/browser/cookie_manager.h
+++ b/android_webview/browser/cookie_manager.h
@@ -49,22 +49,56 @@
   void SetMojoCookieManager(
       network::mojom::CookieManagerPtrInfo cookie_manager_info);
 
-  void SetShouldAcceptCookies(bool accept);
-  bool GetShouldAcceptCookies();
-  void SetCookie(const GURL& host,
-                 const std::string& cookie_value,
-                 base::OnceCallback<void(bool)> callback);
-  void SetCookieSync(const GURL& host, const std::string& cookie_value);
-  std::string GetCookie(const GURL& host);
-  void RemoveSessionCookies(base::OnceCallback<void(bool)> callback);
-  void RemoveAllCookies(base::OnceCallback<void(bool)> callback);
-  void RemoveAllCookiesSync();
-  void RemoveSessionCookiesSync();
-  void RemoveExpiredCookies();
-  void FlushCookieStore();
-  bool HasCookies();
+  void SetShouldAcceptCookies(JNIEnv* env,
+                              const base::android::JavaParamRef<jobject>& obj,
+                              jboolean accept);
+  jboolean GetShouldAcceptCookies(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void SetCookie(JNIEnv* env,
+                 const base::android::JavaParamRef<jobject>& obj,
+                 const base::android::JavaParamRef<jstring>& url,
+                 const base::android::JavaParamRef<jstring>& value,
+                 const base::android::JavaParamRef<jobject>& java_callback);
+  void SetCookieSync(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& obj,
+                     const base::android::JavaParamRef<jstring>& url,
+                     const base::android::JavaParamRef<jstring>& value);
+
+  base::android::ScopedJavaLocalRef<jstring> GetCookie(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& url);
+
+  void RemoveAllCookies(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& java_callback);
+  void RemoveSessionCookies(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& java_callback);
+  void RemoveAllCookiesSync(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj);
+  void RemoveSessionCookiesSync(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void RemoveExpiredCookies(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj);
+  void FlushCookieStore(JNIEnv* env,
+                        const base::android::JavaParamRef<jobject>& obj);
+  jboolean HasCookies(JNIEnv* env,
+                      const base::android::JavaParamRef<jobject>& obj);
   bool AllowFileSchemeCookies();
-  void SetAcceptFileSchemeCookies(bool accept);
+  jboolean AllowFileSchemeCookies(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void SetAcceptFileSchemeCookies(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      jboolean accept);
+
+  base::FilePath GetCookieStorePath();
 
  private:
   friend struct base::LazyInstanceTraitsBase<CookieManager>;
@@ -136,6 +170,9 @@
   void AllowFileSchemeCookiesCompleted(base::OnceClosure complete,
                                        bool* result,
                                        bool value);
+  void MigrateCookieStorePath();
+
+  base::FilePath cookie_store_path_;
 
   // This protects the following two bools, as they're used on multiple threads.
   base::Lock accept_file_scheme_cookies_lock_;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
index 6eef540..157d50e 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
@@ -21,13 +21,19 @@
  */
 @JNINamespace("android_webview")
 public final class AwCookieManager {
+    private long mNativeCookieManager;
 
     public AwCookieManager() {
+        this(nativeGetDefaultCookieManager());
+    }
+
+    public AwCookieManager(long nativeCookieManager) {
         try {
             LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_WEBVIEW);
         } catch (ProcessInitException e) {
             throw new RuntimeException("Error initializing WebView library", e);
         }
+        mNativeCookieManager = nativeCookieManager;
     }
 
     /**
@@ -35,7 +41,7 @@
      * @param accept TRUE if accept cookie
      */
     public void setAcceptCookie(boolean accept) {
-        nativeSetShouldAcceptCookies(accept);
+        nativeSetShouldAcceptCookies(mNativeCookieManager, accept);
     }
 
     /**
@@ -43,7 +49,7 @@
      * @return TRUE if accept cookie
      */
     public boolean acceptCookie() {
-        return nativeGetShouldAcceptCookies();
+        return nativeGetShouldAcceptCookies(mNativeCookieManager);
     }
 
     /**
@@ -51,21 +57,21 @@
      */
     public void setCookie(String url, String value) {
         UrlValue pair = fixupUrlValue(url, value);
-        nativeSetCookieSync(pair.mUrl, pair.mValue);
+        nativeSetCookieSync(mNativeCookieManager, pair.mUrl, pair.mValue);
     }
 
     /**
      * Deprecated synchronous version of removeSessionCookies.
      */
     public void removeSessionCookies() {
-        nativeRemoveSessionCookiesSync();
+        nativeRemoveSessionCookiesSync(mNativeCookieManager);
     }
 
     /**
      * Deprecated synchronous version of removeAllCookies.
      */
     public void removeAllCookies() {
-        nativeRemoveAllCookiesSync();
+        nativeRemoveAllCookiesSync(mNativeCookieManager);
     }
 
     /**
@@ -79,7 +85,8 @@
     public void setCookie(final String url, final String value, final Callback<Boolean> callback) {
         try {
             UrlValue pair = fixupUrlValue(url, value);
-            nativeSetCookie(pair.mUrl, pair.mValue, new CookieCallback(callback));
+            nativeSetCookie(
+                    mNativeCookieManager, pair.mUrl, pair.mValue, new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "SetCookie must be called on a thread with a running Looper.");
@@ -93,7 +100,7 @@
      * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
      */
     public String getCookie(final String url) {
-        String cookie = nativeGetCookie(url.toString());
+        String cookie = nativeGetCookie(mNativeCookieManager, url.toString());
         // Return null if the string is empty to match legacy behavior
         return cookie == null || cookie.trim().isEmpty() ? null : cookie;
     }
@@ -105,7 +112,7 @@
      */
     public void removeSessionCookies(Callback<Boolean> callback) {
         try {
-            nativeRemoveSessionCookies(new CookieCallback(callback));
+            nativeRemoveSessionCookies(mNativeCookieManager, new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "removeSessionCookies must be called on a thread with a running Looper.");
@@ -119,7 +126,7 @@
      */
     public void removeAllCookies(Callback<Boolean> callback) {
         try {
-            nativeRemoveAllCookies(new CookieCallback(callback));
+            nativeRemoveAllCookies(mNativeCookieManager, new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "removeAllCookies must be called on a thread with a running Looper.");
@@ -130,25 +137,25 @@
      *  Return true if there are stored cookies.
      */
     public boolean hasCookies() {
-        return nativeHasCookies();
+        return nativeHasCookies(mNativeCookieManager);
     }
 
     /**
      * Remove all expired cookies
      */
     public void removeExpiredCookies() {
-        nativeRemoveExpiredCookies();
+        nativeRemoveExpiredCookies(mNativeCookieManager);
     }
 
     public void flushCookieStore() {
-        nativeFlushCookieStore();
+        nativeFlushCookieStore(mNativeCookieManager);
     }
 
     /**
      * Whether cookies are accepted for file scheme URLs.
      */
     public boolean allowFileSchemeCookies() {
-        return nativeAllowFileSchemeCookies();
+        return nativeAllowFileSchemeCookies(mNativeCookieManager);
     }
 
     /**
@@ -161,7 +168,7 @@
      * instance has been created.
      */
     public void setAcceptFileSchemeCookies(boolean accept) {
-        nativeSetAcceptFileSchemeCookies(accept);
+        nativeSetAcceptFileSchemeCookies(mNativeCookieManager, accept);
     }
 
     /**
@@ -234,22 +241,26 @@
         return new UrlValue(url, value);
     }
 
-    private native void nativeSetShouldAcceptCookies(boolean accept);
-    private native boolean nativeGetShouldAcceptCookies();
+    private static native long nativeGetDefaultCookieManager();
 
-    private native void nativeSetCookie(String url, String value, CookieCallback callback);
-    private native void nativeSetCookieSync(String url, String value);
-    private native String nativeGetCookie(String url);
+    private native void nativeSetShouldAcceptCookies(long nativeCookieManager, boolean accept);
+    private native boolean nativeGetShouldAcceptCookies(long nativeCookieManager);
 
-    private native void nativeRemoveSessionCookies(CookieCallback callback);
-    private native void nativeRemoveSessionCookiesSync();
-    private native void nativeRemoveAllCookies(CookieCallback callback);
-    private native void nativeRemoveAllCookiesSync();
-    private native void nativeRemoveExpiredCookies();
-    private native void nativeFlushCookieStore();
+    private native void nativeSetCookie(
+            long nativeCookieManager, String url, String value, CookieCallback callback);
+    private native void nativeSetCookieSync(long nativeCookieManager, String url, String value);
+    private native String nativeGetCookie(long nativeCookieManager, String url);
 
-    private native boolean nativeHasCookies();
+    private native void nativeRemoveSessionCookies(
+            long nativeCookieManager, CookieCallback callback);
+    private native void nativeRemoveSessionCookiesSync(long nativeCookieManager);
+    private native void nativeRemoveAllCookies(long nativeCookieManager, CookieCallback callback);
+    private native void nativeRemoveAllCookiesSync(long nativeCookieManager);
+    private native void nativeRemoveExpiredCookies(long nativeCookieManager);
+    private native void nativeFlushCookieStore(long nativeCookieManager);
 
-    private native boolean nativeAllowFileSchemeCookies();
-    private native void nativeSetAcceptFileSchemeCookies(boolean accept);
+    private native boolean nativeHasCookies(long nativeCookieManager);
+
+    private native boolean nativeAllowFileSchemeCookies(long nativeCookieManager);
+    private native void nativeSetAcceptFileSchemeCookies(long nativeCookieManager, boolean accept);
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java
index 84e17af..160b317 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java
@@ -20,6 +20,7 @@
 
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.AwContentsClient.AwWebResourceRequest;
+import org.chromium.base.BuildInfo;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.net.test.EmbeddedTestServer;
@@ -65,12 +66,13 @@
             String url = mTestServer.getURL("/android_webview/test/data/hello_world.html");
             mActivityTestRule.loadUrlSync(
                     mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
-            // TODO(ntfschr): update this assertion whenever
-            // https://android.googlesource.com/platform/external/conscrypt/+/1d6a0b8453054b7dd703693f2ce2896ae061aee3
-            // rolls into an Android release, as this will mean Android intends to distrust SHA1
-            // (http://crbug.com/919749).
-            Assert.assertEquals("We should not have received any SSL errors", count,
-                    onReceivedSslErrorHelper.getCallCount());
+            if (BuildInfo.isAtLeastQ()) {
+                Assert.assertEquals("We should generate an SSL error on >= Q", count + 1,
+                        onReceivedSslErrorHelper.getCallCount());
+            } else {
+                Assert.assertEquals("We should not have received any SSL errors on < Q", count,
+                        onReceivedSslErrorHelper.getCallCount());
+            }
         } finally {
             mTestServer.stopAndDestroyServer();
         }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/OnDiskFileTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/OnDiskFileTest.java
index d8a292fb..97cf008 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/OnDiskFileTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/OnDiskFileTest.java
@@ -80,7 +80,7 @@
                                                   .getTargetContext()
                                                   .getDir("webview", Context.MODE_PRIVATE)
                                                   .getPath(),
-                "Cookies");
+                "Default/Cookies");
         webViewCookiePath.delete();
 
         // Set a cookie and flush it to disk. This should guarantee the cookie file is created.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index 8ea47a9..33fe165 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -568,31 +568,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    public void testSafeBrowsingWhitelistHardcodedWebUiPageBackToSafety() throws Throwable {
-        mContentsClient.setSafeBrowsingAction(SafeBrowsingAction.BACK_TO_SAFETY);
-
-        loadGreenPage();
-        mActivityTestRule.loadUrlSync(
-                mAwContents, mContentsClient.getOnPageFinishedHelper(), WEB_UI_MALWARE_URL);
-        OnReceivedError2Helper errorHelper = mContentsClient.getOnReceivedError2Helper();
-        int errorCount = errorHelper.getCallCount();
-        errorHelper.waitForCallback(errorCount);
-        Assert.assertEquals(
-                ErrorCodeConversionHelper.ERROR_UNSAFE_RESOURCE, errorHelper.getError().errorCode);
-        Assert.assertEquals("Network error is for the malicious page", WEB_UI_MALWARE_URL,
-                errorHelper.getRequest().url);
-
-        assertGreenPageShowing();
-
-        // Check onSafeBrowsingHit arguments
-        Assert.assertEquals(WEB_UI_MALWARE_URL, mContentsClient.getLastRequest().url);
-        Assert.assertEquals(AwSafeBrowsingConversionHelper.SAFE_BROWSING_THREAT_MALWARE,
-                mContentsClient.getLastThreatType());
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"AndroidWebView"})
     public void testCallbackCalledOnSafeBrowsingBadWhitelistRule() throws Throwable {
         verifyWhiteListRule("http://www.google.com", false);
     }
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index fc01c4d6..76aefa5f 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -303,15 +303,15 @@
     }
     layer->SetOpacity(opacity);
 
-    int initial_y_ = 0;
+    int initial_y = 0;
     if (translation_y_map_.contains(window))
-      initial_y_ = translation_y_map_[window];
+      initial_y = translation_y_map_[window];
 
     // Alter the y-translation. Offset by the window location relative to the
     // grid.
     gfx::Transform transform = layer->transform();
     transform.matrix().setFloat(1, 3,
-                                static_cast<float>(initial_y_ - new_grid_y));
+                                static_cast<float>(initial_y - new_grid_y));
     layer->SetTransform(transform);
 
     // Return the first layer for the caller to observe.
@@ -423,18 +423,11 @@
   translation_y_map_.clear();
   aura::Window::Windows windows = GetWindowsForHomeGesture();
   for (auto* window : windows) {
-    // There is a bug where the first OverviewItem |window_| will always return
-    // the identity, even though a transform has been visually applied. For this
-    // case use the y location of the screen bounds.
-    // TODO(sammiequon): Investigate why this is happening and remove the if
-    // clause.
-    if (window->transform().IsIdentity() &&
-        (window == GetWindow() ||
-         ::wm::HasTransientAncestor(window, GetWindow()))) {
-      translation_y_map_[window] = window->GetBoundsInScreen().y();
-    } else {
-      translation_y_map_[window] = window->transform().To2dTranslation().y();
-    }
+    // Cache the original y translation when setting bounds. They will be
+    // possibly used later when swiping up from the shelf to close overview. Use
+    // the target transform as some windows may still be animating.
+    translation_y_map_[window] =
+        window->layer()->GetTargetTransform().To2dTranslation().y();
   }
 }
 
@@ -553,7 +546,8 @@
 void OverviewItem::OnSelectorItemDragEnded(bool snap) {
   if (is_being_dragged_) {
     is_being_dragged_ = false;
-    // Do nothing further with the dragged overview item if it is being snapped.
+    // Do nothing further with the dragged overview item if it is being
+    // snapped.
     if (snap)
       return;
     // Re-show shadow for the dragged overview item after drag ends.
@@ -611,8 +605,8 @@
 
   should_restack_on_animation_end_ = false;
 
-  // First stack this item's window below the snapped window if split view mode
-  // is active.
+  // First stack this item's window below the snapped window if split view
+  // mode is active.
   aura::Window* dragged_window = GetWindow();
   aura::Window* dragged_widget_window = item_widget_->GetNativeWindow();
   aura::Window* parent_window = dragged_widget_window->parent();
@@ -701,10 +695,9 @@
 }
 
 void OverviewItem::UpdateRoundedCornersAndShadow() {
-  // Do not show the rounded corners and the shadow if overview is shutting down
-  // or we're currently in entering overview animation.
-  // Also don't update or animate the window's frame header clip under these
-  // conditions.
+  // Do not show the rounded corners and the shadow if overview is shutting
+  // down or we're currently in entering overview animation. Also don't update
+  // or animate the window's frame header clip under these conditions.
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   const bool is_shutting_down =
       !overview_controller || !overview_controller->InOverviewSession();
@@ -741,8 +734,8 @@
 void OverviewItem::OnStartingAnimationComplete() {
   DCHECK(item_widget_);
   if (transform_window_.IsMinimized()) {
-    // Fade the title in if minimized. The rest of |item_widget_| should already
-    // be shown.
+    // Fade the title in if minimized. The rest of |item_widget_| should
+    // already be shown.
     caption_container_view_->SetHeaderVisibility(
         CaptionContainerView::HeaderVisibility::kVisible);
   } else {
@@ -920,8 +913,8 @@
     if (window == GetWindow()) {
       caption_container_view_->UpdatePreviewView();
     } else {
-      // Transient window is repositioned. The new position within the overview
-      // item needs to be recomputed.
+      // Transient window is repositioned. The new position within the
+      // overview item needs to be recomputed.
       SetBounds(target_bounds_, OVERVIEW_ANIMATION_NONE);
     }
   }
@@ -946,8 +939,9 @@
 void OverviewItem::OnWindowTitleChanged(aura::Window* window) {
   if (window != GetWindow())
     return;
-  // TODO(flackr): Maybe add the new title to a vector of titles so that we can
-  // filter any of the titles the window had while in the overview session.
+  // TODO(flackr): Maybe add the new title to a vector of titles so that we
+  // can filter any of the titles the window had while in the overview
+  // session.
   caption_container_view_->SetTitle(window->GetTitle());
 }
 
@@ -1091,8 +1085,8 @@
 
 void OverviewItem::HandlePressEvent(const gfx::PointF& location_in_screen,
                                     bool from_touch_gesture) {
-  // We allow switching finger while dragging, but do not allow dragging two or
-  // more items.
+  // We allow switching finger while dragging, but do not allow dragging two
+  // or more items.
   if (overview_session_->window_drag_controller() &&
       overview_session_->window_drag_controller()->item()) {
     return;
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 3d910d5..0951d06 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -639,8 +639,12 @@
     grid->OnStartingAnimationComplete(canceled);
 
   if (!canceled) {
-    if (overview_focus_widget_)
-      overview_focus_widget_->Show();
+    if (overview_focus_widget_) {
+      if (enter_exit_overview_type_ == EnterExitOverviewType::kStartUnfocused)
+        overview_focus_widget_->ShowInactive();
+      else
+        overview_focus_widget_->Show();
+    }
     Shell::Get()->overview_controller()->DelayedUpdateRoundedCornersAndShadow();
   }
 }
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 0fecfe38..d1fc3b04 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -89,7 +89,11 @@
     // animations. This is used when performing the desk switch animation when
     // the source desk is in overview mode, while the target desk is not.
     // This should not be used for entering overview mode.
-    kImmediateExit
+    kImmediateExit,
+    // Prevents overview from stealing the input focus. Used by code that starts
+    // overview after a window has already been snapped in split view. The
+    // purpose is so that overview does not steal focus from the snapped window.
+    kStartUnfocused,
   };
 
   // Callback which fills out the passed settings object. Used by several
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 42601a1..0e3526f7 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -17,6 +17,7 @@
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_session.h"
 #include "ash/wm/tablet_mode/internal_input_devices_event_blocker.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
 #include "ash/wm/window_state.h"
@@ -1011,7 +1012,8 @@
   const auto state = Shell::Get()->split_view_controller()->state();
   if (state == SplitViewState::kLeftSnapped ||
       state == SplitViewState::kRightSnapped) {
-    Shell::Get()->overview_controller()->StartOverview();
+    Shell::Get()->overview_controller()->StartOverview(
+        OverviewSession::EnterExitOverviewType::kStartUnfocused);
   }
 
   UpdateInternalInputDevicesEventBlocker();
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index f3836c84..fb3dd8f 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -1150,6 +1150,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if the active window is snapped on the right before tablet mode,
@@ -1162,6 +1163,7 @@
   EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is snapped on the left and
@@ -1237,6 +1239,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(left_window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is a transient child of a
@@ -1254,6 +1257,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(parent.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(parent.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is the app list and the
@@ -1270,6 +1274,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is being dragged and the
@@ -1292,6 +1297,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(snapped_window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is hidden from overview
@@ -1311,6 +1317,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(snapped_window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is snapped on the left but
@@ -1399,6 +1406,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(left_window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if before tablet mode, the active window is snapped on the right
@@ -1429,6 +1437,7 @@
   EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(right_window.get(), window_util::GetActiveWindow());
 }
 
 // Test that if overview is triggered on entering tablet mode, then the app list
@@ -1455,6 +1464,7 @@
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window1.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+  EXPECT_EQ(window1.get(), window_util::GetActiveWindow());
 }
 
 // Test that it is okay to write code that first starts split view by snapping a
diff --git a/base/android/jni_generator/golden/testProxyNatives.golden b/base/android/jni_generator/golden/testProxyNatives.golden
index 2ac9308..a6bd014 100644
--- a/base/android/jni_generator/golden/testProxyNatives.golden
+++ b/base/android/jni_generator/golden/testProxyNatives.golden
@@ -23,13 +23,14 @@
 
 
 // Step 3: Method stubs.
-static void JNI_SampleProxyJni_Foo(JNIEnv* env);
-
 JNI_GENERATOR_EXPORT void
     Java_org_chromium_base_natives_GEN_1JNI_org_1chromium_1example_1SampleProxyJni_1foo(
     JNIEnv* env,
-    jclass jcaller) {
-  return JNI_SampleProxyJni_Foo(env);
+    jclass jcaller,
+    jlong nativePtr) {
+  FooAndroid::BarDelegate* native = reinterpret_cast<FooAndroid::BarDelegate*>(nativePtr);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Foo");
+  return native->Foo(env);
 }
 
 static jint JNI_SampleProxyJni_Bar(JNIEnv* env, jint x,
diff --git a/base/android/jni_generator/golden/testProxyNativesJava.golden b/base/android/jni_generator/golden/testProxyNativesJava.golden
index ab6039a..eeca79f7 100644
--- a/base/android/jni_generator/golden/testProxyNativesJava.golden
+++ b/base/android/jni_generator/golden/testProxyNativesJava.golden
@@ -12,7 +12,7 @@
   public static final boolean TESTING_ENABLED = false;
   public static final boolean REQUIRE_MOCK = false;
 
-  public static native void org_chromium_example_SampleProxyJni_foo();
+  public static native void org_chromium_example_SampleProxyJni_foo(long nativePtr);
 
   public static native int org_chromium_example_SampleProxyJni_bar(int x, int y);
 
diff --git a/base/android/jni_generator/golden/testProxyNativesRegistrations.golden b/base/android/jni_generator/golden/testProxyNativesRegistrations.golden
index ec95de61..f976834 100644
--- a/base/android/jni_generator/golden/testProxyNativesRegistrations.golden
+++ b/base/android/jni_generator/golden/testProxyNativesRegistrations.golden
@@ -25,7 +25,8 @@
 JNI_GENERATOR_EXPORT void
     Java_org_chromium_base_natives_GEN_1JNI_org_1chromium_1example_1SampleProxyJni_1foo(
     JNIEnv* env,
-    jclass jcaller);
+    jclass jcaller,
+    jlong nativePtr);
 JNI_GENERATOR_EXPORT jint
     Java_org_chromium_base_natives_GEN_1JNI_org_1chromium_1example_1SampleProxyJni_1bar(
     JNIEnv* env,
@@ -44,7 +45,7 @@
 
 
 static const JNINativeMethod kMethods_org_chromium_base_natives_GEN_1JNI[] = {
-    { "org_chromium_example_SampleProxyJni_foo", "()V",
+    { "org_chromium_example_SampleProxyJni_foo", "(J)V",
         reinterpret_cast<void*>(Java_org_chromium_base_natives_GEN_1JNI_org_1chromium_1example_1SampleProxyJni_1foo)
         },
     { "org_chromium_example_SampleProxyJni_bar", "(II)I",
diff --git a/base/android/jni_generator/golden/testStaticBindingCaller.golden b/base/android/jni_generator/golden/testStaticBindingCaller.golden
index f618859..df55ec4 100644
--- a/base/android/jni_generator/golden/testStaticBindingCaller.golden
+++ b/base/android/jni_generator/golden/testStaticBindingCaller.golden
@@ -87,5 +87,14 @@
   return native->CallNativeMethod(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
+JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeCallWithQualifiedObject(
+    JNIEnv* env,
+    jobject jcaller,
+    jlong nativePtr) {
+  Foo::Bar* native = reinterpret_cast<Foo::Bar*>(nativePtr);
+  CHECK_NATIVE_PTR(env, jcaller, native, "CallWithQualifiedObject");
+  return native->CallWithQualifiedObject(env, base::android::JavaParamRef<jobject>(env, jcaller));
+}
+
 
 #endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 06ba6bd1..4dc400fd 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -52,6 +52,8 @@
 # doesn't require name to be prefixed with native, and does not
 # require a native qualifier.
 _EXTRACT_METHODS_REGEX = re.compile(
+    r'(@NativeClassQualifiedName'
+    r'\(\"(?P<native_class_name>.*?)\"\)\s*)?'
     r'(?P<qualifiers>'
     r'((public|private|static|final|abstract|protected|native)\s*)*)\s+'
     r'(?P<return_type>\S*)\s+'
@@ -919,7 +921,6 @@
         name = method.group('name')
         params = JniParams.Parse(method.group('params'), use_proxy_types=True)
         return_type = JavaTypeToProxyCast(method.group('return_type'))
-
         unescaped_proxy_name = ProxyHelpers.CreateProxyMethodName(
             fully_qualified_class, name, use_hash)
         native = NativeMethod(
@@ -927,6 +928,7 @@
             java_class_name=None,
             return_type=return_type,
             name=name,
+            native_class_name=method.group('native_class_name'),
             params=params,
             is_proxy=True,
             proxy_name=unescaped_proxy_name,
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index ce530b36..240750d 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -228,16 +228,13 @@
             static=False,
             name='Init',
             params=[],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='void',
             static=False,
             name='Destroy',
             params=[Param(datatype='int', name='nativeChromeBrowserProvider')],
-            java_class_name=None,
-            type='method',
-            p0_type='ChromeBrowserProvider'),
+            java_class_name=None),
         NativeMethod(
             return_type='long',
             static=False,
@@ -249,16 +246,13 @@
                 Param(datatype='boolean', name='isFolder'),
                 Param(datatype='long', name='parentId')
             ],
-            java_class_name=None,
-            type='method',
-            p0_type='ChromeBrowserProvider'),
+            java_class_name=None),
         NativeMethod(
             return_type='String',
             static=True,
             name='GetDomainAndRegistry',
             params=[Param(datatype='String', name='url')],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='void',
             static=True,
@@ -267,22 +261,19 @@
                 Param(datatype='byte[]', name='state'),
                 Param(datatype='int', name='tab_index')
             ],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='byte[]',
             static=False,
             name='GetStateAsByteArray',
             params=[Param(datatype='View', name='view')],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='String[]',
             static=True,
             name='GetAutofillProfileGUIDs',
             params=[],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='void',
             static=False,
@@ -291,8 +282,7 @@
                 Param(datatype='int', name='sessionId'),
                 Param(datatype='String[]', name='results')
             ],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='long',
             static=False,
@@ -307,23 +297,19 @@
                 Param(datatype='String', name='title'),
                 Param(datatype='Integer', name='visits')
             ],
-            java_class_name=None,
-            type='method',
-            p0_type='ChromeBrowserProvider'),
+            java_class_name=None),
         NativeMethod(
             return_type='int',
             static=False,
             name='FindAll',
             params=[Param(datatype='String', name='find')],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='OnFrameAvailableListener',
             static=True,
             name='GetInnerClass',
             params=[],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='Bitmap',
             static=False,
@@ -335,9 +321,7 @@
                 Param(datatype='String[]', name='selectionArgs'),
                 Param(datatype='String', name='sortOrder'),
             ],
-            java_class_name=None,
-            type='method',
-            p0_type='ChromeBrowserProvider'),
+            java_class_name=None),
         NativeMethod(
             return_type='void',
             static=False,
@@ -348,16 +332,13 @@
                 Param(datatype='double', name='beta'),
                 Param(datatype='double', name='gamma'),
             ],
-            java_class_name=None,
-            type='method',
-            p0_type='content::DataFetcherImplAndroid'),
+            java_class_name=None),
         NativeMethod(
             return_type='Throwable',
             static=True,
             name='MessWithJavaException',
             params=[Param(datatype='Throwable', name='e')],
-            java_class_name=None,
-            type='function')
+            java_class_name=None)
     ]
     self.AssertListEquals(golden_natives, natives)
     h1 = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
@@ -391,8 +372,7 @@
             static=False,
             name='Init',
             params=[],
-            java_class_name='MyInnerClass',
-            type='function')
+            java_class_name='MyInnerClass')
     ]
     self.AssertListEquals(golden_natives, natives)
     jni_params = jni_generator.JniParams('')
@@ -419,15 +399,13 @@
             static=False,
             name='Init',
             params=[],
-            java_class_name='MyInnerClass',
-            type='function'),
+            java_class_name='MyInnerClass'),
         NativeMethod(
             return_type='int',
             static=False,
             name='Init',
             params=[],
-            java_class_name='MyOtherInnerClass',
-            type='function')
+            java_class_name='MyOtherInnerClass')
     ]
     self.AssertListEquals(golden_natives, natives)
     jni_params = jni_generator.JniParams('')
@@ -453,15 +431,13 @@
             static=False,
             name='Init',
             params=[],
-            java_class_name=None,
-            type='function'),
+            java_class_name=None),
         NativeMethod(
             return_type='int',
             static=False,
             name='Init',
             params=[],
-            java_class_name='MyOtherInnerClass',
-            type='function')
+            java_class_name='MyOtherInnerClass')
     ]
     self.AssertListEquals(golden_natives, natives)
     jni_params = jni_generator.JniParams('')
@@ -1098,8 +1074,6 @@
             name='Destroy',
             params=[Param(datatype='long', name='nativeChromeBrowserProvider')],
             java_class_name=None,
-            type='method',
-            p0_type='ChromeBrowserProvider',
             ptr_type=test_options.ptr_type),
     ]
     self.AssertListEquals(golden_natives, natives)
@@ -1279,6 +1253,8 @@
       static native void nativeFoo(long nativeNativeObject, Bar caller);
       static native void nativeFoo(long nativeNativeObject, Bar caller, int a);
       native void nativeCallNativeMethod(long nativePtr);
+      @NativeClassQualifiedName("Foo::Bar")
+      native void nativeCallWithQualifiedObject(long nativePtr);
     }
     """
 
@@ -1352,8 +1328,7 @@
             params=[],
             java_class_name=None,
             is_proxy=True,
-            proxy_name='org_chromium_example_SampleProxyJni_foo_1bar',
-            type='function'),
+            proxy_name='org_chromium_example_SampleProxyJni_foo_1bar'),
         NativeMethod(
             return_type='void',
             static=True,
@@ -1361,8 +1336,7 @@
             params=[],
             java_class_name=None,
             is_proxy=True,
-            proxy_name='org_chromium_example_SampleProxyJni_foo_1_1bar',
-            type='function'),
+            proxy_name='org_chromium_example_SampleProxyJni_foo_1_1bar'),
     ]
 
     self.AssertListEquals(natives, golden_natives)
@@ -1404,8 +1378,7 @@
             params=[],
             java_class_name=None,
             is_proxy=True,
-            proxy_name='test_foo_Foo_thisismaindex',
-            type='function'),
+            proxy_name='test_foo_Foo_thisismaindex'),
     ]
 
     self.AssertListEquals(natives, golden_natives)
@@ -1449,7 +1422,8 @@
       private void do_not_match();
       @NativeMethods
       interface Natives {
-        void foo();
+        @NativeClassQualifiedName("FooAndroid::BarDelegate")
+        void foo(long nativePtr);
         int bar(int x, int y);
         String foobar(String x, String y);
       }
@@ -1465,7 +1439,8 @@
       Natives
 
 
-      { void     foo();
+      { @NativeClassQualifiedName("FooAndroid::BarDelegate") void
+    foo(long nativePtr);
       int              bar(int
       x,  int y); String
         foobar(String x, String y);
@@ -1485,11 +1460,12 @@
             return_type='void',
             static=True,
             name='foo',
-            params=[],
+            native_class_name='FooAndroid::BarDelegate',
+            params=[Param(datatype='long', name='nativePtr')],
             java_class_name=None,
             is_proxy=True,
             proxy_name='org_chromium_example_SampleProxyJni_foo',
-            type='function'),
+            ptr_type='long'),
         NativeMethod(
             return_type='int',
             static=True,
@@ -1500,8 +1476,7 @@
             ],
             java_class_name=None,
             is_proxy=True,
-            proxy_name='org_chromium_example_SampleProxyJni_bar',
-            type='function'),
+            proxy_name='org_chromium_example_SampleProxyJni_bar'),
         NativeMethod(
             return_type='String',
             static=True,
@@ -1512,8 +1487,7 @@
             ],
             java_class_name=None,
             is_proxy=True,
-            proxy_name='org_chromium_example_SampleProxyJni_foobar',
-            type='function'),
+            proxy_name='org_chromium_example_SampleProxyJni_foobar'),
     ]
     self.AssertListEquals(golden_natives, natives)
     self.AssertListEquals(golden_natives, bad_spacing_natives)
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index 3ec75056..b3996c4 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -346,7 +346,7 @@
         build_utils.AddToZipHermetic(out_apk, apk_path, data='')
 
       # 5. Resources
-      for info in resource_infos:
+      for info in sorted(resource_infos, key=lambda i: i.filename):
         if info.filename != 'AndroidManifest.xml':
           copy_resource(info)
 
@@ -355,7 +355,7 @@
       # Prebuilt jars may contain class files which we shouldn't include.
       for java_resource in options.java_resources:
         with zipfile.ZipFile(java_resource, 'r') as java_resource_jar:
-          for apk_path in java_resource_jar.namelist():
+          for apk_path in sorted(java_resource_jar.namelist()):
             apk_path_lower = apk_path.lower()
 
             if apk_path_lower.startswith('meta-inf/'):
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 3451a10..caf29df5 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -98,7 +98,7 @@
 SCREENSHOTS_DIR = os.path.join(DIR_SOURCE_ROOT, 'out_screenshots')
 
 ANDROID_SDK_VERSION = version_codes.OREO_MR1
-ANDROID_SDK_BUILD_TOOLS_VERSION = '27.0.3'
+ANDROID_SDK_BUILD_TOOLS_VERSION = '29.0.2'
 ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'android_sdk',
                                 'public')
 ANDROID_SDK_TOOLS = os.path.join(ANDROID_SDK_ROOT,
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index e74eb5e4..c1bfc87 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -75,7 +75,7 @@
   if (android_sdk_release == "o_mr1") {
     default_android_sdk_root = "//third_party/android_sdk/public"
     default_android_sdk_version = 27
-    default_android_sdk_build_tools_version = "27.0.3"
+    default_android_sdk_build_tools_version = "29.0.2"
     default_android_sdk_tools_version_suffix = "-26.0.0-dev"
     public_android_sdk = true
   }
@@ -83,7 +83,7 @@
   if (android_sdk_release == "p") {
     default_android_sdk_root = "//third_party/android_sdk/public"
     default_android_sdk_version = 28
-    default_android_sdk_build_tools_version = "27.0.3"
+    default_android_sdk_build_tools_version = "29.0.2"
     default_android_sdk_tools_version_suffix = "-26.0.0-dev"
     public_android_sdk = true
   }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 051a70a..5595ec2 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8904978802695676464
\ No newline at end of file
+8904950329177319120
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 00883a9..c68e838e 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8904977342571225392
\ No newline at end of file
+8904949232858181504
\ No newline at end of file
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc
index 16dda2c..fe86b36 100644
--- a/cc/paint/image_transfer_cache_entry.cc
+++ b/cc/paint/image_transfer_cache_entry.cc
@@ -107,8 +107,7 @@
   bool add_mips_after_color_conversion =
       target_color_space && mip_mapped == GrMipMapped::kYes;
   sk_sp<SkImage> uploaded_image = source_image->makeTextureImage(
-      context, nullptr,
-      add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped);
+      context, add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped);
 
   // Step 2: Apply a color-space conversion if necessary.
   if (uploaded_image && target_color_space) {
@@ -125,7 +124,7 @@
     // optimization from GpuImageDecodeCache where we forcefully remove the
     // intermediate from Skia's cache.
     uploaded_image =
-        uploaded_image->makeTextureImage(context, nullptr, GrMipMapped::kYes);
+        uploaded_image->makeTextureImage(context, GrMipMapped::kYes);
   }
 
   return uploaded_image;
@@ -333,8 +332,8 @@
   // 1) Generate mipmap chains if requested.
   if (needs_mips) {
     for (size_t plane = 0; plane < plane_images.size(); plane++) {
-      plane_images[plane] = plane_images[plane]->makeTextureImage(
-          context_, nullptr /* dstColorSpace */, GrMipMapped::kYes);
+      plane_images[plane] =
+          plane_images[plane]->makeTextureImage(context_, GrMipMapped::kYes);
       if (!plane_images[plane]) {
         DLOG(ERROR) << "Could not generate mipmap chain for plane " << plane;
         return false;
@@ -578,7 +577,7 @@
     for (size_t plane = 0; plane < plane_images_.size(); plane++) {
       DCHECK(plane_images_.at(plane));
       sk_sp<SkImage> mipped_plane = plane_images_.at(plane)->makeTextureImage(
-          context_, nullptr /* dstColorSpace */, GrMipMapped::kYes);
+          context_, GrMipMapped::kYes);
       if (!mipped_plane)
         return;
       mipped_planes.push_back(std::move(mipped_plane));
@@ -600,7 +599,7 @@
   // TODO(ericrk): consider adding in the DeleteSkImageAndPreventCaching
   // optimization from GpuImageDecodeCache where we forcefully remove the
   // intermediate from Skia's cache.
-  image_ = image_->makeTextureImage(context_, nullptr, GrMipMapped::kYes);
+  image_ = image_->makeTextureImage(context_, GrMipMapped::kYes);
 }
 
 }  // namespace cc
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc
index 5889e894..6c940ab9 100644
--- a/cc/test/skia_common.cc
+++ b/cc/test/skia_common.cc
@@ -235,9 +235,9 @@
   bitmap.eraseColor(SK_AlphaTRANSPARENT);
   return PaintImageBuilder::WithDefault()
       .set_id(PaintImage::GetNextId())
-      .set_image(SkImage::MakeFromBitmap(bitmap)->makeTextureImage(
-                     context.get(), nullptr),
-                 PaintImage::GetNextContentId())
+      .set_image(
+          SkImage::MakeFromBitmap(bitmap)->makeTextureImage(context.get()),
+          PaintImage::GetNextContentId())
       .TakePaintImage();
 }
 
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 08ba92f5..d8520299 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -460,7 +460,7 @@
   bool add_mips_after_color_conversion =
       (target_color_space && mip_mapped == GrMipMapped::kYes);
   sk_sp<SkImage> uploaded_image = source_image->makeTextureImage(
-      context->GrContext(), nullptr,
+      context->GrContext(),
       add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped);
 
   // Step 2: Apply a color-space conversion if necessary.
@@ -476,8 +476,8 @@
   // add mips here.
   if (uploaded_image && add_mips_after_color_conversion) {
     sk_sp<SkImage> pre_mipped_image = uploaded_image;
-    uploaded_image = uploaded_image->makeTextureImage(
-        context->GrContext(), nullptr, GrMipMapped::kYes);
+    uploaded_image = uploaded_image->makeTextureImage(context->GrContext(),
+                                                      GrMipMapped::kYes);
     DCHECK_NE(pre_mipped_image, uploaded_image);
     DeleteSkImageAndPreventCaching(context, std::move(pre_mipped_image));
   }
@@ -2082,11 +2082,11 @@
       DCHECK(!use_transfer_cache_);
       base::AutoUnlock unlock(lock_);
       uploaded_y_image = uploaded_y_image->makeTextureImage(
-          context_->GrContext(), nullptr /* colorspace */, image_needs_mips);
+          context_->GrContext(), image_needs_mips);
       uploaded_u_image = uploaded_u_image->makeTextureImage(
-          context_->GrContext(), nullptr /* colorspace */, image_needs_mips);
+          context_->GrContext(), image_needs_mips);
       uploaded_v_image = uploaded_v_image->makeTextureImage(
-          context_->GrContext(), nullptr /* colorspace */, image_needs_mips);
+          context_->GrContext(), image_needs_mips);
       if (!uploaded_y_image || !uploaded_u_image || !uploaded_v_image) {
         DLOG(WARNING) << "TODO(crbug.com/740737): Context was lost. Early out.";
         return;
@@ -2836,11 +2836,11 @@
 
     // Generate a new image from the previous, adding mips.
     sk_sp<SkImage> image_y_with_mips = previous_y_image->makeTextureImage(
-        context_->GrContext(), nullptr, GrMipMapped::kYes);
+        context_->GrContext(), GrMipMapped::kYes);
     sk_sp<SkImage> image_u_with_mips = previous_u_image->makeTextureImage(
-        context_->GrContext(), nullptr, GrMipMapped::kYes);
+        context_->GrContext(), GrMipMapped::kYes);
     sk_sp<SkImage> image_v_with_mips = previous_v_image->makeTextureImage(
-        context_->GrContext(), nullptr, GrMipMapped::kYes);
+        context_->GrContext(), GrMipMapped::kYes);
 
     // Handle lost context.
     if (!image_y_with_mips || !image_u_with_mips || !image_v_with_mips) {
@@ -2924,7 +2924,7 @@
 
   // Generate a new image from the previous, adding mips.
   sk_sp<SkImage> image_with_mips = previous_image->makeTextureImage(
-      context_->GrContext(), nullptr, GrMipMapped::kYes);
+      context_->GrContext(), GrMipMapped::kYes);
 
   // Handle lost context.
   if (!image_with_mips) {
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index c30c1b1c..0c641903 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -512,8 +512,7 @@
 
         ASSERT_TRUE(original_uploaded_plane);
         auto plane_with_mips = original_uploaded_plane->makeTextureImage(
-            context_provider()->GrContext(), nullptr /* color space */,
-            GrMipMapped::kYes);
+            context_provider()->GrContext(), GrMipMapped::kYes);
         ASSERT_TRUE(plane_with_mips);
         EXPECT_EQ(should_have_mips, original_uploaded_plane == plane_with_mips);
       }
@@ -2491,8 +2490,7 @@
     } else {
       sk_sp<SkImage> image_with_mips =
           decoded_draw_image.image()->makeTextureImage(
-              context_provider()->GrContext(), nullptr /* color space */,
-              GrMipMapped::kYes);
+              context_provider()->GrContext(), GrMipMapped::kYes);
       EXPECT_EQ(should_have_mips,
                 image_with_mips == decoded_draw_image.image());
     }
@@ -2561,7 +2559,7 @@
     } else {
       sk_sp<SkImage> image_with_mips =
           decoded_draw_image.image()->makeTextureImage(
-              context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+              context_provider()->GrContext(), GrMipMapped::kYes);
       ASSERT_TRUE(image_with_mips);
       EXPECT_NE(image_with_mips, decoded_draw_image.image());
     }
@@ -2609,7 +2607,7 @@
     } else {
       sk_sp<SkImage> image_with_mips =
           decoded_draw_image.image()->makeTextureImage(
-              context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+              context_provider()->GrContext(), GrMipMapped::kYes);
       EXPECT_EQ(image_with_mips, decoded_draw_image.image());
     }
     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
@@ -2663,7 +2661,7 @@
     } else {
       sk_sp<SkImage> image_with_mips =
           decoded_draw_image.image()->makeTextureImage(
-              context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+              context_provider()->GrContext(), GrMipMapped::kYes);
       EXPECT_NE(image_with_mips, decoded_draw_image.image());
     }
     images_to_unlock.push_back({draw_image, decoded_draw_image});
@@ -2704,7 +2702,7 @@
     } else {
       sk_sp<SkImage> image_with_mips =
           decoded_draw_image.image()->makeTextureImage(
-              context_provider()->GrContext(), nullptr, GrMipMapped::kYes);
+              context_provider()->GrContext(), GrMipMapped::kYes);
       EXPECT_EQ(image_with_mips, decoded_draw_image.image());
     }
     images_to_unlock.push_back({draw_image, decoded_draw_image});
diff --git a/chrome/android/OWNERS b/chrome/android/OWNERS
index 20c4daa..1df4384 100644
--- a/chrome/android/OWNERS
+++ b/chrome/android/OWNERS
@@ -1,5 +1,6 @@
 agrieve@chromium.org
 dtrainor@chromium.org
+mthiesse@chromium.org
 nyquist@chromium.org
 tedchoc@chromium.org
 twellington@chromium.org
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
index 7727c6a..6391ee97 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -133,6 +133,7 @@
     @Features.EnableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION + "<Study")
     @CommandLineFlags.Add({BASE_PARAMS})
     @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
+    @DisabledTest(message = "crbug.com/991852 This test is flaky")
     public void testTabToGridFromLiveTabAnimation() throws InterruptedException {
         // clang-format on
         assertTrue(FeatureUtilities.isTabToGtsAnimationEnabled());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index 81a6987..c2e506d7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -977,10 +977,9 @@
     }
 
     int indexOfSelected() {
-        if (mNextTabId != Tab.INVALID_TAB_ID) {
-            return getIndexOfTab(
-                    TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), mNextTabId),
-                    !mActionsOnAllRelatedTabs);
+        Tab nextTab = TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), mNextTabId);
+        if (nextTab != null) {
+            return getIndexOfTab(nextTab, !mActionsOnAllRelatedTabs);
         }
 
         return mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter().index();
diff --git a/chrome/android/java/res/drawable-hdpi/ic_lightbulb_outline_googblue_24dp.png b/chrome/android/java/res/drawable-hdpi/ic_lightbulb_outline_googblue_24dp.png
new file mode 100644
index 0000000..6fc3ca4f
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/ic_lightbulb_outline_googblue_24dp.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ic_lightbulb_outline_googblue_24dp.png b/chrome/android/java/res/drawable-mdpi/ic_lightbulb_outline_googblue_24dp.png
new file mode 100644
index 0000000..399ac87c
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/ic_lightbulb_outline_googblue_24dp.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ic_lightbulb_outline_googblue_24dp.png b/chrome/android/java/res/drawable-xhdpi/ic_lightbulb_outline_googblue_24dp.png
new file mode 100644
index 0000000..4c7db9b9
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/ic_lightbulb_outline_googblue_24dp.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ic_lightbulb_outline_googblue_24dp.png b/chrome/android/java/res/drawable-xxhdpi/ic_lightbulb_outline_googblue_24dp.png
new file mode 100644
index 0000000..5bac05e
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/ic_lightbulb_outline_googblue_24dp.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ic_lightbulb_outline_googblue_24dp.png b/chrome/android/java/res/drawable-xxxhdpi/ic_lightbulb_outline_googblue_24dp.png
new file mode 100644
index 0000000..09dc764
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/ic_lightbulb_outline_googblue_24dp.png
Binary files differ
diff --git a/chrome/android/java/res/layout/button_preference_button.xml b/chrome/android/java/res/layout/button_preference_button.xml
index f1fdeece..fc189fc 100644
--- a/chrome/android/java/res/layout/button_preference_button.xml
+++ b/chrome/android/java/res/layout/button_preference_button.xml
@@ -3,13 +3,11 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<!-- Layout used by ButtonPreference for the button widget style.
-     android:focusable="false" makes it possible to trigger an event with the 'ENTER' key.
-     See crbug.com/674736 -->
+<!-- Layout used by ButtonPreference for the button widget style. -->
 <org.chromium.ui.widget.ButtonCompat
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/button_preference"
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
-    android:focusable="false"
+    android:focusable="true"
     style="@style/FilledButton" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java
index 616a2a6..08759438 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java
@@ -226,8 +226,9 @@
             selection.add(item);
         }
 
-        // TODO(finnur): Do this asynchronously to make the number roll view show the right number.
-        mSelectionDelegate.setSelectedItems(selection);
+        // Post a runnable to update the selection so that the update occurs after the search fully
+        // finishes, ensuring the number roll shows the right number.
+        getHandler().post(() -> mSelectionDelegate.setSelectedItems(selection));
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
index 1d16e4e..da7b94b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
@@ -16,6 +16,7 @@
 import android.view.View;
 import android.webkit.MimeTypeMap;
 
+import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.task.AsyncTask;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.download.DownloadManagerService;
 import org.chromium.chrome.browser.download.DownloadMetrics;
 import org.chromium.chrome.browser.download.DownloadUtils;
+import org.chromium.components.download.DownloadCollectionBridge;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -74,7 +76,6 @@
      * @param template Template of the text to be displayed.
      */
     private CharSequence getDownloadMessageText(final Context context, final String template) {
-        // TODO(qinmin): fix the case that mFilePath is a content Uri.
         final File file = new File(mFilePath);
         final Uri fileUri = Uri.fromFile(file);
         final String mimeType = getMimeTypeFromUri(fileUri);
@@ -82,24 +83,32 @@
         return getMessageText(template, filename, new ClickableSpan() {
             @Override
             public void onClick(View view) {
-                new AsyncTask<Boolean>() {
+                new AsyncTask<String>() {
                     @Override
-                    protected Boolean doInBackground() {
-                        return new File(mFilePath).exists();
+                    protected String doInBackground() {
+                        if (BuildInfo.isAtLeastQ()
+                                && DownloadCollectionBridge.getDownloadCollectionBridge()
+                                           .needToPublishDownload(mFilePath)) {
+                            Uri uri = DownloadCollectionBridge.getDownloadCollectionBridge()
+                                              .getDownloadUriForFileName(filename);
+                            return uri == null ? null : uri.toString();
+                        } else {
+                            if (file.exists()) return mFilePath;
+                            return null;
+                        }
                     }
 
                     @Override
-                    protected void onPostExecute(Boolean fileExists) {
-                        if (fileExists) {
-                            DownloadUtils.openFile(mFilePath, mimeType, null, mIsIncognito, null,
+                    protected void onPostExecute(String filePath) {
+                        if (filePath != null) {
+                            DownloadUtils.openFile(filePath, mimeType, null, mIsIncognito, null,
                                     null, DownloadMetrics.DownloadOpenSource.INFO_BAR);
                         } else {
                             DownloadManagerService.openDownloadsPage(
                                     ContextUtils.getApplicationContext());
                         }
                     }
-                }
-                        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
             }
         });
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
index eff2e2b..d5b866c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
@@ -144,14 +144,11 @@
             event.setAddedCount(addedCount);
             mDelegate.sendAccessibilityEventUnchecked(event);
         }
-        if (oldState.getSelStart() != newState.getSelEnd()
+
+        if (oldState.getSelStart() != newState.getSelStart()
                 || oldState.getSelEnd() != newState.getSelEnd()) {
-            AccessibilityEvent event =
-                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
-            event.setFromIndex(newState.getSelStart());
-            event.setToIndex(newState.getSelEnd());
-            event.setItemCount(newState.getUserText().length());
-            mDelegate.sendAccessibilityEventUnchecked(event);
+            mDelegate.sendAccessibilityEventUnchecked(
+                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
index a0ad8f5..9fa5685c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
@@ -26,7 +26,9 @@
         super(context, attrs);
         setLayoutResource(R.layout.button_preference_layout);
         setWidgetLayoutResource(R.layout.button_preference_button);
-        setSelectable(true);
+
+        // Only the inner button element should be focusable.
+        setSelectable(false);
     }
 
     @Override
@@ -39,8 +41,5 @@
                 getOnPreferenceClickListener().onPreferenceClick(ButtonPreference.this);
             }
         });
-
-        // Prevent triggering an event after tapping any part of the view that is not the button.
-        holder.itemView.setClickable(false);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferenceFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferenceFragment.java
index 21da79c..ed4bf62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferenceFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferenceFragment.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.preferences.datareduction;
 
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.support.graphics.drawable.VectorDrawableCompat;
@@ -112,6 +113,15 @@
         return false;
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Force rebinding of preferences on orientation change, otherwise the usage chart will not
+        // be correctly redrawn: https://crbug.com/994668.
+        getListView().getAdapter().notifyDataSetChanged();
+
+        super.onConfigurationChanged(newConfig);
+    }
+
     /**
      * Switches preference screens depending on whether data reduction is enabled/disabled.
      * @param isEnabled Indicates whether data reduction is enabled.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
index 576a820..604a6b0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
@@ -1173,6 +1173,10 @@
         if (!isUsingSpannableModel()) mInOrder.verify(mVerifier).onUpdateSelection(len, len);
         verifyOnPopulateAccessibilityEvent(
                 AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, url, "", 18, 18, 18, -1, -1);
+        if (isUsingSpannableModel()) {
+            verifyOnPopulateAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED,
+                    url, "", 18, 0, 18, -1, -1);
+        }
         mInOrder.verify(mVerifier).onUpdateSelection(0, len);
         verifyOnPopulateAccessibilityEvent(
                 AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, url, "", 18, 0, 18, -1, -1);
@@ -1180,7 +1184,9 @@
                 AccessibilityEvent.TYPE_VIEW_FOCUSED, url, "", 2, -1, -1, -1, -1);
 
         if (isUsingSpannableModel()) {
-            assertVerifierCallCounts(1, 3);
+            // TODO(https://crbug.com/935785): Remove this exception when double announcement is
+            // fixed; we expect to see same results as with non-spannable model.
+            assertVerifierCallCounts(1, 4);
         } else {
             assertVerifierCallCounts(2, 3);
         }
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index ce191ba..21b029c 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -452,7 +452,6 @@
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
       "//chromeos/services/cellular_setup/public/mojom",
-      "//chromeos/services/device_sync/public/cpp:manifest",
       "//chromeos/services/ime/public/mojom",
       "//chromeos/services/media_perception/public/mojom",
       "//chromeos/services/multidevice_setup/public/cpp:manifest",
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index 0e2131c..5c036e82 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -50,7 +50,6 @@
 #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision.mojom.h"
 #include "chrome/browser/ui/webui/chromeos/machine_learning/machine_learning_internals_page_handler.mojom.h"
 #include "chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom.h"
-#include "chromeos/services/device_sync/public/cpp/manifest.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
 #include "chromeos/services/media_perception/public/mojom/media_perception.mojom.h"
 #include "chromeos/services/multidevice_setup/public/cpp/manifest.h"
@@ -122,7 +121,6 @@
         .RequireCapability("device", "device:geolocation_config")
         .RequireCapability("device", "device:geolocation_control")
         .RequireCapability("device", "device:ip_geolocator")
-        .RequireCapability("device_sync", "device_sync")
         .RequireCapability("identity", "identity_accessor")
         .RequireCapability(image_annotation::mojom::kServiceName,
                            image_annotation::mojom::kAnnotationCapability)
@@ -194,7 +192,6 @@
                 extensions::mime_handler::BeforeUnloadControl,
                 extensions::mime_handler::MimeHandlerService,
 #endif
-                image_annotation::mojom::Annotator,
                 media::mojom::MediaEngagementScoreDetailsProvider,
                 media_router::mojom::MediaRouter,
                 page_load_metrics::mojom::PageLoadMetrics,
@@ -229,7 +226,6 @@
         .PackageService(image_annotation::GetManifest())
         .PackageService(prefs::GetManifest())
 #if defined(OS_CHROMEOS)
-        .PackageService(chromeos::device_sync::GetManifest())
         .PackageService(chromeos::multidevice_setup::GetManifest())
 #endif  // defined(OS_CHROMEOS)
 #if !defined(OS_ANDROID)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d66d517..028c958 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5143,8 +5143,71 @@
       <message name="IDS_NTP_CUSTOMIZE_DEFAULT_LABEL" desc="The label for the Default theme in the customization menu on the New Tab Page">
         Default
       </message>
-      <message name="IDS_NTP_CUSTOMIZE_COLOR_LABEL_PREFIX" desc="The label prefix for the color options in the customization menu on the New Tab Page. It is followed by a hex value in #000000 format">
-        Hex color value
+      <message name="IDS_NTP_COLORS_WARM_GREY" desc="A color option in the customization menu on the New Tab Page.">
+        Warm grey
+      </message>
+      <message name="IDS_NTP_COLORS_COOL_GREY" desc="A color option in the customization menu on the New Tab Page.">
+        Cool grey
+      </message>
+      <message name="IDS_NTP_COLORS_MIDNIGHT_BLUE" desc="A color option in the customization menu on the New Tab Page.">
+        Midnight blue
+      </message>
+      <message name="IDS_NTP_COLORS_BLACK" desc="A color option in the customization menu on the New Tab Page.">
+        Black
+      </message>
+      <message name="IDS_NTP_COLORS_BEIGE_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Beige and white
+      </message>
+      <message name="IDS_NTP_COLORS_YELLOW_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Yellow and white
+      </message>
+      <message name="IDS_NTP_COLORS_GREEN_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Green and white
+      </message>
+      <message name="IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Light teal and white
+      </message>
+      <message name="IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Light purple and white
+      </message>
+      <message name="IDS_NTP_COLORS_PINK_AND_WHITE" desc="A color option in the customization menu on the New Tab Page.">
+        Pink and white
+      </message>
+      <message name="IDS_NTP_COLORS_BEIGE" desc="A color option in the customization menu on the New Tab Page.">
+        Beige
+      </message>
+      <message name="IDS_NTP_COLORS_ORANGE" desc="A color option in the customization menu on the New Tab Page.">
+        Orange
+      </message>
+      <message name="IDS_NTP_COLORS_LIGHT_GREEN" desc="A color option in the customization menu on the New Tab Page.">
+        Light green
+      </message>
+      <message name="IDS_NTP_COLORS_LIGHT_TEAL" desc="A color option in the customization menu on the New Tab Page.">
+        Light teal
+      </message>
+      <message name="IDS_NTP_COLORS_LIGHT_BLUE" desc="A color option in the customization menu on the New Tab Page.">
+        Light blue
+      </message>
+      <message name="IDS_NTP_COLORS_PINK" desc="A color option in the customization menu on the New Tab Page.">
+        Pink
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_PINK_AND_RED" desc="A color option in the customization menu on the New Tab Page.">
+        Dark pink and red
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_RED_AND_ORANGE" desc="A color option in the customization menu on the New Tab Page.">
+        Dark red and orange
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_GREEN" desc="A color option in the customization menu on the New Tab Page.">
+        Dark green
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_TEAL" desc="A color option in the customization menu on the New Tab Page.">
+        Dark teal
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_BLUE" desc="A color option in the customization menu on the New Tab Page.">
+        Dark blue
+      </message>
+      <message name="IDS_NTP_COLORS_DARK_PURPLE" desc="A color option in the customization menu on the New Tab Page.">
+        Dark purple
       </message>
 
       <if expr="is_android">
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE.png.sha1
new file mode 100644
index 0000000..3267e08
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE.png.sha1
@@ -0,0 +1 @@
+aaca00cd574be037909ed84839aa6a709dd35073
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE_AND_WHITE.png.sha1
new file mode 100644
index 0000000..9a75c02
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BEIGE_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+d5727ef7e683a5ed47b118105e09863ba2a9e3a4
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BLACK.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BLACK.png.sha1
new file mode 100644
index 0000000..e5d4e80
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_BLACK.png.sha1
@@ -0,0 +1 @@
+29e470489950e45e96093a23f4c14425a43c17ae
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_COOL_GREY.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_COOL_GREY.png.sha1
new file mode 100644
index 0000000..03be823
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_COOL_GREY.png.sha1
@@ -0,0 +1 @@
+2d7fde5147964e1bb7818decfcde484b80486ae7
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_BLUE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_BLUE.png.sha1
new file mode 100644
index 0000000..8ab8b632
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_BLUE.png.sha1
@@ -0,0 +1 @@
+c34140a6e2f432f917514088b83d435557edc104
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_GREEN.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_GREEN.png.sha1
new file mode 100644
index 0000000..3822bdf4
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_GREEN.png.sha1
@@ -0,0 +1 @@
+84aabc09c99db9d3490c2ad1f50dce422e2bb1c4
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PINK_AND_RED.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PINK_AND_RED.png.sha1
new file mode 100644
index 0000000..1a9353f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PINK_AND_RED.png.sha1
@@ -0,0 +1 @@
+75853c7674bb6f2da42b4c6faf35f1cf2c0b6cf2
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PURPLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PURPLE.png.sha1
new file mode 100644
index 0000000..4f829da
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_PURPLE.png.sha1
@@ -0,0 +1 @@
+ffed6551c33c5cf03a6139a8ad2474403aeb1af4
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_RED_AND_ORANGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_RED_AND_ORANGE.png.sha1
new file mode 100644
index 0000000..80c9c7f4
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_RED_AND_ORANGE.png.sha1
@@ -0,0 +1 @@
+006a81b67f0b6bc2802cb6bc1b5bf6073ad75411
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_TEAL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_TEAL.png.sha1
new file mode 100644
index 0000000..e7c5cc86
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_DARK_TEAL.png.sha1
@@ -0,0 +1 @@
+d0b4bd1de7206f37a6816653fa991cfd9231e366
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_GREEN_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_GREEN_AND_WHITE.png.sha1
new file mode 100644
index 0000000..73883a5e
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_GREEN_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+926c1e44562b3b1fcaf544ecf4661b24340ba504
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_BLUE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_BLUE.png.sha1
new file mode 100644
index 0000000..5b9de805
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_BLUE.png.sha1
@@ -0,0 +1 @@
+7dc45c2e6f19555fa62aa909027372fd09c1ceba
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_GREEN.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_GREEN.png.sha1
new file mode 100644
index 0000000..370211ec
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_GREEN.png.sha1
@@ -0,0 +1 @@
+8e5156f345da382f38dbe87ea00cee35be90d91a
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE.png.sha1
new file mode 100644
index 0000000..90487d6
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+c9182088d5a69c60472c080043fa449186e80d8b
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL.png.sha1
new file mode 100644
index 0000000..ceed8a3
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL.png.sha1
@@ -0,0 +1 @@
+15cf7583f8520b86869c20dc31db2618da292af7
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE.png.sha1
new file mode 100644
index 0000000..f2e99393
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+a01d20a7acfbc6434361d2738921061e6a2fab10
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_MIDNIGHT_BLUE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_MIDNIGHT_BLUE.png.sha1
new file mode 100644
index 0000000..cc5f47f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_MIDNIGHT_BLUE.png.sha1
@@ -0,0 +1 @@
+83aab3a1cfcc0eccab6e71a78f7f235c0f9fba4e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_ORANGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_ORANGE.png.sha1
new file mode 100644
index 0000000..5f1b206
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_ORANGE.png.sha1
@@ -0,0 +1 @@
+fc172b85a6672bdd5cd11176117887fbad9d0365
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK.png.sha1
new file mode 100644
index 0000000..e32a336
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK.png.sha1
@@ -0,0 +1 @@
+66626ef90b525007a8715634b1109de11aa9c202
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK_AND_WHITE.png.sha1
new file mode 100644
index 0000000..8990df0
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_PINK_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+207b1710865c47723e743a7b610ebe5c68a39a6c
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_WARM_GREY.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_WARM_GREY.png.sha1
new file mode 100644
index 0000000..977d9e2
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_WARM_GREY.png.sha1
@@ -0,0 +1 @@
+715f96f78193dbefeeac3d5f1311199090a2170e
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COLORS_YELLOW_AND_WHITE.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_YELLOW_AND_WHITE.png.sha1
new file mode 100644
index 0000000..e5918bda
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_COLORS_YELLOW_AND_WHITE.png.sha1
@@ -0,0 +1 @@
+ec2525b597c9d3e004e2708c71f623a8e1ed15b7
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_LABEL_PREFIX.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_LABEL_PREFIX.png.sha1
deleted file mode 100644
index 52951f5..0000000
--- a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOMIZE_COLOR_LABEL_PREFIX.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-dcf786564be1d6de14b8636caf742fc922ee4344
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index b4b81e0..1d3a57ac 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -5241,10 +5241,10 @@
   <message name="IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR" desc="An error message shown when a user attempts to view the credentials on their security key (an authentication hardware device), but an error with the device was encountered.">
     Your security key couldn't be read
   </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_SUCCESS" desc="Label of a button that lets a user delete individual credentials on their security key (an authentication hardware device).">
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_SUCCESS" desc="A confirmation message shown when a user deletes an individual credential on their security key (an authentication hardware device).">
     Your sign-in data was deleted
   </message>
-  <message name="IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_FAILED" desc="Label of a button that lets a user delete individual credentials on their security key (an authentication hardware device).">
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_FAILED" desc="An error message shown when a user attempts to delete an individual credential on their security key (an authentication hardware device).">
     Your sign-in data couldn't be deleted
   </message>
   <message name="IDS_SETTINGS_SECURITY_KEYS_BIO_ENROLLMENT_SUBPAGE_DESCRIPTION" desc="The description for a menu item that when clicked lets the user view, add, rename, and delete fingerprints on their security key (an authentication hardware device).">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 1bed3bf..122e93c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -265,6 +265,8 @@
     "chrome_browser_application_mac.mm",
     "chrome_browser_field_trials.cc",
     "chrome_browser_field_trials.h",
+    "chrome_browser_interface_binders.cc",
+    "chrome_browser_interface_binders.h",
     "chrome_browser_main.cc",
     "chrome_browser_main.h",
     "chrome_browser_main_android.cc",
@@ -3655,7 +3657,6 @@
       "//chromeos/services/assistant/public:feature_flags",
       "//chromeos/services/assistant/public/cpp:prefs",
       "//chromeos/services/cellular_setup",
-      "//chromeos/services/device_sync",
       "//chromeos/services/device_sync/public/mojom",
       "//chromeos/services/multidevice_setup",
       "//chromeos/services/multidevice_setup/public/cpp:first_run_field_trial",
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index 46cdc36..08a3c9c 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -66,3 +66,7 @@
 per-file unload_browsertest.cc=file://content/OWNERS
 
 per-file web_bluetooth*=file://content/browser/bluetooth/OWNERS
+
+# For security review.
+per-file chrome_browser_interface_binders.cc=set noparent
+per-file chrome_browser_interface_binders.cc=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/android/OWNERS b/chrome/browser/android/OWNERS
index cce02a0..83bd31ce 100644
--- a/chrome/browser/android/OWNERS
+++ b/chrome/browser/android/OWNERS
@@ -1,7 +1,4 @@
-dtrainor@chromium.org
-nyquist@chromium.org
-tedchoc@chromium.org
-yfriedman@chromium.org
+file://chrome/android/OWNERS
 
 per-file shortcut_*=dominickn@chromium.org
 
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index dc2d0ded..a5bd724 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -57,6 +57,8 @@
                     R.drawable.infobar_protected_media_identifier)
 DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_SAVE_PASSWORD,
                     R.drawable.ic_vpn_key_blue)
+DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_TIP,
+                    R.drawable.ic_lightbulb_outline_googblue_24dp)
 DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_TRANSLATE, R.drawable.infobar_translate)
 DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_WARNING, R.drawable.infobar_warning)
 LINK_RESOURCE_ID(IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER,
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
new file mode 100644
index 0000000..02a15d3c
--- /dev/null
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chrome_browser_interface_binders.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "services/image_annotation/public/mojom/constants.mojom-forward.h"
+#include "services/image_annotation/public/mojom/image_annotation.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace chrome {
+namespace internal {
+
+// Forward image Annotator requests to the image_annotation service.
+void BindImageAnnotator(
+    content::RenderFrameHost* const frame_host,
+    mojo::PendingReceiver<image_annotation::mojom::Annotator> receiver) {
+  content::BrowserContext::GetConnectorFor(
+      frame_host->GetProcess()->GetBrowserContext())
+      ->BindInterface(
+          image_annotation::mojom::kServiceName,
+          image_annotation::mojom::AnnotatorRequest(std::move(receiver)));
+}
+
+void PopulateChromeFrameBinders(
+    service_manager::BinderMapWithContext<content::RenderFrameHost*>* map) {
+  map->Add<image_annotation::mojom::Annotator>(
+      base::BindRepeating(&BindImageAnnotator));
+}
+
+}  // namespace internal
+}  // namespace chrome
diff --git a/chrome/browser/chrome_browser_interface_binders.h b/chrome/browser/chrome_browser_interface_binders.h
new file mode 100644
index 0000000..8141dde
--- /dev/null
+++ b/chrome/browser/chrome_browser_interface_binders.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_
+#define CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_
+
+#include "services/service_manager/public/cpp/binder_map.h"
+
+namespace content {
+
+class RenderFrameHost;
+}  // namespace content
+
+namespace chrome {
+namespace internal {
+
+// PopulateChromeFrameBinders() registers BrowserInterfaceBroker's
+// GetInterface() handler callbacks for chrome-specific document-scoped
+// interfaces. This mechanism will replace interface registries and binders used
+// for handling InterfaceProvider's GetInterface() calls (see crbug.com/718652).
+void PopulateChromeFrameBinders(
+    service_manager::BinderMapWithContext<content::RenderFrameHost*>* map);
+
+}  // namespace internal
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_CHROME_BROWSER_INTERFACE_BINDERS_H_
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index acb600d..7356a14b 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -46,6 +46,7 @@
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/cache_stats_recorder.h"
+#include "chrome/browser/chrome_browser_interface_binders.h"
 #include "chrome/browser/chrome_content_browser_client_parts.h"
 #include "chrome/browser/chrome_quota_permission_context.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
@@ -322,14 +323,10 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "ppapi/host/ppapi_host.h"
 #include "printing/buildflags/buildflags.h"
-#include "services/image_annotation/public/mojom/constants.mojom.h"
-#include "services/image_annotation/public/mojom/image_annotation.mojom.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/service_manager/embedder/switches.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/mojom/connector.mojom.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
 #include "services/service_manager/sandbox/switches.h"
 #include "services/strings/grit/services_strings.h"
@@ -3758,6 +3755,11 @@
 #endif
 }
 
+void ChromeContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
+    service_manager::BinderMapWithContext<content::RenderFrameHost*>* map) {
+  chrome::internal::PopulateChromeFrameBinders(map);
+}
+
 void ChromeContentBrowserClient::BindInterfaceRequestFromFrame(
     content::RenderFrameHost* render_frame_host,
     const std::string& interface_name,
@@ -4322,14 +4324,6 @@
   }
 }
 
-// Forward image Annotator requests to the image_annotation service.
-void BindImageAnnotator(image_annotation::mojom::AnnotatorRequest request,
-                        RenderFrameHost* const frame_host) {
-  content::BrowserContext::GetConnectorFor(
-      frame_host->GetProcess()->GetBrowserContext())
-      ->BindInterface(image_annotation::mojom::kServiceName,
-                      std::move(request));
-}
 
 void ChromeContentBrowserClient::InitWebContextInterfaces() {
   frame_interfaces_ = std::make_unique<service_manager::BinderRegistry>();
@@ -4345,8 +4339,6 @@
 
   frame_interfaces_parameterized_->AddInterface(
       base::Bind(&InsecureSensitiveInputDriverFactory::BindDriver));
-  frame_interfaces_parameterized_->AddInterface(
-      base::BindRepeating(&BindImageAnnotator));
 
 #if defined(OS_ANDROID)
   frame_interfaces_parameterized_->AddInterface(base::Bind(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 4a2fe52..46985d2c 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -374,6 +374,9 @@
   void ExposeInterfacesToMediaService(
       service_manager::BinderRegistry* registry,
       content::RenderFrameHost* render_frame_host) override;
+  void RegisterBrowserInterfaceBindersForFrame(
+      service_manager::BinderMapWithContext<content::RenderFrameHost*>* map)
+      override;
   void BindInterfaceRequestFromFrame(
       content::RenderFrameHost* render_frame_host,
       const std::string& interface_name,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 78f5a6b..f01fd2e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -128,6 +128,7 @@
     "//chromeos/services/assistant/public/cpp:prefs",
     "//chromeos/services/cros_healthd/public/cpp",
     "//chromeos/services/cros_healthd/public/mojom",
+    "//chromeos/services/device_sync",
     "//chromeos/services/device_sync/public/cpp",
     "//chromeos/services/ime:constants",
     "//chromeos/services/ime/public/cpp:buildflags",
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index 456e554b..fc7ee2c 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -300,6 +300,24 @@
       {"(", container_id.first, ", ", container_id.second, ")"});
 }
 
+bool IsUninstallable(Profile* profile, const std::string& app_id) {
+  if (!IsCrostiniEnabled(profile))
+    return false;
+  if (app_id == kCrostiniTerminalId &&
+      !crostini::CrostiniManager::GetForProfile(profile)
+           ->GetInstallerViewStatus()) {
+    // Crostini should not be uninstalled if the installer is still running.
+    return true;
+  }
+  CrostiniRegistryService* registry_service =
+      CrostiniRegistryServiceFactory::GetForProfile(profile);
+  base::Optional<CrostiniRegistryService::Registration> registration =
+      registry_service->GetRegistration(app_id);
+  if (registration)
+    return registration->CanUninstall();
+  return false;
+}
+
 bool IsCrostiniAllowedForProfile(Profile* profile) {
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index bf9f6c8..9320ed03 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -39,6 +39,9 @@
 // Return" (<vm_name>, <container_name>)".
 std::string ContainerIdToString(const ContainerId& container_id);
 
+// Checks if user profile is able to a crostini app with a given app_id.
+bool IsUninstallable(Profile* profile, const std::string& app_id);
+
 // Returns true if crostini is allowed to run for |profile|.
 // Otherwise, returns false, e.g. if crostini is not available on the device,
 // or it is in the flow to set up managed account creation.
diff --git a/chrome/browser/chromeos/device_sync/device_sync_client_factory.cc b/chrome/browser/chromeos/device_sync/device_sync_client_factory.cc
index c7697851..03bb64f 100644
--- a/chrome/browser/chromeos/device_sync/device_sync_client_factory.cc
+++ b/chrome/browser/chromeos/device_sync/device_sync_client_factory.cc
@@ -5,19 +5,28 @@
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
 
 #include "base/macros.h"
+#include "chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.h"
+#include "chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service_factory.h"
+#include "chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_features.h"
+#include "chromeos/services/device_sync/device_sync_service.h"
 #include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
 #include "chromeos/services/device_sync/public/cpp/device_sync_client_impl.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
+#include "components/gcm_driver/gcm_profile_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
 
@@ -33,14 +42,37 @@
       Profile::FromBrowserContext(context)->GetPrefs());
 }
 
+std::unique_ptr<DeviceSyncService> CreateServiceInstanceForProfile(
+    Profile* profile,
+    mojo::Remote<chromeos::device_sync::mojom::DeviceSyncService>* remote) {
+  mojo::Remote<chromeos::device_sync::mojom::DeviceSyncServiceInitializer>
+      initializer;
+  auto service = std::make_unique<DeviceSyncService>(
+      IdentityManagerFactory::GetForProfile(profile),
+      gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
+      chromeos::GcmDeviceInfoProviderImpl::GetInstance(),
+      chromeos::ClientAppMetadataProviderServiceFactory::GetForProfile(profile),
+      profile->GetURLLoaderFactory(), initializer.BindNewPipeAndPassReceiver());
+  mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector;
+  content::BrowserContext::GetConnectorFor(profile)->Connect(
+      prefs::mojom::kServiceName,
+      pref_store_connector.InitWithNewPipeAndPassReceiver());
+  initializer->Initialize(remote->BindNewPipeAndPassReceiver(),
+                          std::move(pref_store_connector));
+  return service;
+}
+
 }  // namespace
 
 // Class that wraps DeviceSyncClient in a KeyedService.
 class DeviceSyncClientHolder : public KeyedService {
  public:
   explicit DeviceSyncClientHolder(content::BrowserContext* context)
-      : device_sync_client_(DeviceSyncClientImpl::Factory::Get()->BuildInstance(
-            content::BrowserContext::GetConnectorFor(context))) {}
+      : service_(CreateServiceInstanceForProfile(
+            Profile::FromBrowserContext(context),
+            &remote_service_)),
+        device_sync_client_(DeviceSyncClientImpl::Factory::Get()->BuildInstance(
+            remote_service_.get())) {}
 
   DeviceSyncClient* device_sync_client() { return device_sync_client_.get(); }
 
@@ -48,6 +80,12 @@
   // KeyedService:
   void Shutdown() override { device_sync_client_.reset(); }
 
+  mojo::Remote<chromeos::device_sync::mojom::DeviceSyncService> remote_service_;
+
+  // The in-process service instance. Never exposed publicly except through the
+  // DeviceSyncClient, which is isolated from the service by Mojo interfaces.
+  std::unique_ptr<chromeos::device_sync::DeviceSyncService> service_;
+
   std::unique_ptr<DeviceSyncClient> device_sync_client_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceSyncClientHolder);
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index 9b99955d..1f90b1c 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -565,7 +565,7 @@
       has_managed_image_(false),
       weak_factory_(this) {
   background_task_runner_ = base::CreateSequencedTaskRunner(
-      {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+      {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE,
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
 }
 
diff --git a/chrome/browser/chromeos/tether/tether_service_unittest.cc b/chrome/browser/chromeos/tether/tether_service_unittest.cc
index c06bcf7..7c7be0ef 100644
--- a/chrome/browser/chromeos/tether/tether_service_unittest.cc
+++ b/chrome/browser/chromeos/tether/tether_service_unittest.cc
@@ -267,7 +267,7 @@
 
   // chromeos::device_sync::DeviceSyncClientImpl::Factory:
   std::unique_ptr<chromeos::device_sync::DeviceSyncClient> BuildInstance(
-      service_manager::Connector* connector) override {
+      chromeos::device_sync::mojom::DeviceSyncService* service) override {
     auto fake_device_sync_client =
         std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>();
     fake_device_sync_client->NotifyReady();
diff --git a/chrome/browser/extensions/extension_management_internal.cc b/chrome/browser/extensions/extension_management_internal.cc
index c6ee887..6b1e7cc2e 100644
--- a/chrome/browser/extensions/extension_management_internal.cc
+++ b/chrome/browser/extensions/extension_management_internal.cc
@@ -137,10 +137,7 @@
         URLPattern pattern(extension_scheme_mask);
         if (unparsed_str != URLPattern::kAllUrlsPattern)
           unparsed_str.append("/*");
-        // TODO(nrpeter): Remove effective TLD wildcard capability from
-        // URLPattern.
-        URLPattern::ParseResult parse_result = pattern.Parse(
-            unparsed_str, URLPattern::DENY_WILDCARD_FOR_EFFECTIVE_TLD);
+        URLPattern::ParseResult parse_result = pattern.Parse(unparsed_str);
         if (parse_result != URLPattern::ParseResult::kSuccess) {
           LOG(WARNING) << kMalformedPreferenceWarning;
           LOG(WARNING) << "Invalid URL pattern '" + unparsed_str +
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
index 9790299..e9a6890 100644
--- a/chrome/browser/extensions/policy_handlers.cc
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -306,16 +306,13 @@
           std::string unparsed_url;
           unparsed_urls->GetString(i, &unparsed_url);
           URLPattern pattern(extension_scheme_mask);
-          URLPattern::ParseResult parse_result = pattern.Parse(
-              unparsed_url, URLPattern::DENY_WILDCARD_FOR_EFFECTIVE_TLD);
+          URLPattern::ParseResult parse_result = pattern.Parse(unparsed_url);
           // These keys don't support paths due to how we track the initiator
           // of a webRequest and cookie security policy. We expect a valid
           // pattern to return a PARSE_ERROR_EMPTY_PATH.
           if (parse_result == URLPattern::ParseResult::kEmptyPath) {
             // Add a wildcard path to the URL as it should match any path.
-            parse_result =
-                pattern.Parse(unparsed_url + "/*",
-                              URLPattern::DENY_WILDCARD_FOR_EFFECTIVE_TLD);
+            parse_result = pattern.Parse(unparsed_url + "/*");
           } else if (parse_result == URLPattern::ParseResult::kSuccess) {
             // The user supplied a path, notify them that this is not supported.
             if (!pattern.match_all_urls()) {
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tip_infobar_delegate.cc b/chrome/browser/lookalikes/safety_tips/safety_tip_infobar_delegate.cc
index 1aaf560b2..5a31b0a 100644
--- a/chrome/browser/lookalikes/safety_tips/safety_tip_infobar_delegate.cc
+++ b/chrome/browser/lookalikes/safety_tips/safety_tip_infobar_delegate.cc
@@ -88,7 +88,7 @@
 }
 
 int SafetyTipInfoBarDelegate::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_WARNING;
+  return IDR_ANDROID_INFOBAR_TIP;
 }
 
 void SafetyTipInfoBarDelegate::InfoBarDismissed() {
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
index 17e7486..f4302c69 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
@@ -34,6 +34,21 @@
   return lhs->create_time <= rhs->create_time;
 }
 
+void ValidateNotificationParams(const NotificationParams& params) {
+  // Validate time window.
+  DCHECK(params.schedule_params.deliver_time_start.has_value() &&
+         params.schedule_params.deliver_time_end.has_value())
+      << "Currently only support deliver in a time window,";
+  DCHECK(params.schedule_params.deliver_time_start.value() <=
+         params.schedule_params.deliver_time_end.value());
+
+  // Validate ihnr buttons option.
+  if (params.enable_ihnr_buttons) {
+    DCHECK(params.notification_data.buttons.empty())
+        << "Can't have custom buttons when have helpful/unhelpful buttons.";
+  }
+}
+
 class ScheduledNotificationManagerImpl : public ScheduledNotificationManager {
  public:
   using NotificationStore = std::unique_ptr<CollectionStore<NotificationEntry>>;
@@ -77,8 +92,9 @@
       return;
     }
 
+    ValidateNotificationParams(*notification_params);
+
     if (notification_params->enable_ihnr_buttons) {
-      DCHECK(notification_params->notification_data.buttons.empty());
       CreateInhrButtonsPair(&notification_params->notification_data.buttons);
     }
 
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
index 70367367..8e0bf4e5 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
@@ -194,6 +194,10 @@
   schedule_params.priority = ScheduleParams::Priority::kLow;
   auto params = std::make_unique<NotificationParams>(
       SchedulerClientType::kTest1, notification_data, schedule_params);
+  params->schedule_params.deliver_time_start = base::Time::Now();
+  params->schedule_params.deliver_time_end =
+      base::Time::Now() + base::TimeDelta::FromDays(1);
+
   params->enable_ihnr_buttons = true;
   std::string guid = params->guid;
   EXPECT_FALSE(guid.empty());
@@ -218,6 +222,7 @@
   EXPECT_EQ(base::UTF16ToUTF8(entry->notification_data.title), kTitle);
   EXPECT_EQ(entry->schedule_params.priority, ScheduleParams::Priority::kLow);
 
+  // Verify that |enable_ihnr_buttons| will add the helpful/unhelpful buttons.
   auto buttons = entry->notification_data.buttons;
   EXPECT_EQ(buttons.size(), 2u);
   EXPECT_EQ(buttons[0].id, notifications::kDefaultHelpfulButtonId);
@@ -231,6 +236,9 @@
   InitWithData(std::vector<NotificationEntry>());
   auto params = std::make_unique<NotificationParams>(
       SchedulerClientType::kTest1, NotificationData(), ScheduleParams());
+  params->schedule_params.deliver_time_start = base::Time::Now();
+  params->schedule_params.deliver_time_end =
+      base::Time::Now() + base::TimeDelta::FromDays(1);
 
   // Verify call contract.
   EXPECT_CALL(*notification_store(), Add(_, _, _));
diff --git a/chrome/browser/notifications/scheduler/public/schedule_params.h b/chrome/browser/notifications/scheduler/public/schedule_params.h
index 2350304..c4c967a 100644
--- a/chrome/browser/notifications/scheduler/public/schedule_params.h
+++ b/chrome/browser/notifications/scheduler/public/schedule_params.h
@@ -42,7 +42,8 @@
   // The start time of the deliver time window of the notification.
   base::Optional<base::Time> deliver_time_start;
 
-  // The end time of the deliver time window of the notification.
+  // The end time of the deliver time window of the notification. Use in pair
+  // with |deliver_time_start|.
   base::Optional<base::Time> deliver_time_end;
 };
 
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 4fc5122..9c77c71b 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -2326,8 +2326,9 @@
 }
 
 // Checks that prerenders are aborted when an incognito profile is closed.
+// ToDo(crbug.com/994068): The test is crashing on multiple platforms.
 IN_PROC_BROWSER_TEST_F(PrerenderIncognitoBrowserTest,
-                       PrerenderIncognitoClosed) {
+                       DISABLED_PrerenderIncognitoClosed) {
   std::unique_ptr<TestPrerender> prerender = PrerenderTestURL(
       "/prerender/prerender_page.html", FINAL_STATUS_PROFILE_DESTROYED, 1);
   current_browser()->window()->Close();
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 18738b2..bd21561 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -58,7 +58,6 @@
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
 #include "chrome/browser/download/download_manager_utils.h"
-#include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/media/media_device_id_salt.h"
 #include "chrome/browser/native_file_system/chrome_native_file_system_permission_context.h"
 #include "chrome/browser/native_file_system/native_file_system_permission_context_factory.h"
@@ -118,7 +117,6 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/browser/data_store_impl.h"
-#include "components/gcm_driver/gcm_profile_service.h"
 #include "components/history/core/common/pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/simple_dependency_manager.h"
@@ -137,6 +135,7 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/url_formatter/url_fixer.h"
 #include "components/user_prefs/user_prefs.h"
+#include "components/version_info/channel.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cors_origin_pattern_setter.h"
@@ -171,8 +170,6 @@
 #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
 #include "chrome/browser/chromeos/arc/arc_service_launcher.h"
 #include "chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h"
-#include "chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service.h"
-#include "chrome/browser/chromeos/cryptauth/client_app_metadata_provider_service_factory.h"
 #include "chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/chromeos/locale_change_guard.h"
@@ -190,8 +187,6 @@
 #include "chrome/browser/signin/chrome_device_id_helper.h"
 #include "chromeos/components/account_manager/account_manager.h"
 #include "chromeos/components/account_manager/account_manager_factory.h"
-#include "chromeos/services/device_sync/device_sync_service.h"
-#include "chromeos/services/device_sync/public/mojom/constants.mojom.h"
 #include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
 #include "chromeos/services/multidevice_setup/public/mojom/constants.mojom.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
@@ -1315,15 +1310,6 @@
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
-  if (service_name == chromeos::device_sync::mojom::kServiceName) {
-    return std::make_unique<chromeos::device_sync::DeviceSyncService>(
-        IdentityManagerFactory::GetForProfile(this),
-        gcm::GCMProfileServiceFactory::GetForProfile(this)->driver(),
-        chromeos::GcmDeviceInfoProviderImpl::GetInstance(),
-        chromeos::ClientAppMetadataProviderServiceFactory::GetForProfile(this),
-        GetURLLoaderFactory(), std::move(request));
-  }
-
   if (service_name == chromeos::multidevice_setup::mojom::kServiceName) {
     chromeos::android_sms::AndroidSmsService* android_sms_service =
         chromeos::android_sms::AndroidSmsServiceFactory::GetForBrowserContext(
diff --git a/chrome/browser/resources/chromeos/add_supervision/add_supervision.html b/chrome/browser/resources/chromeos/add_supervision/add_supervision.html
index 52f7eaa2..2259d170 100644
--- a/chrome/browser/resources/chromeos/add_supervision/add_supervision.html
+++ b/chrome/browser/resources/chromeos/add_supervision/add_supervision.html
@@ -72,7 +72,7 @@
           <div class="title">$i18n{networkDownHeading}</div>
           <div class="sub-title">$i18n{networkDownDescription}</div>
           <div id="networkUnavailableDiv">
-            <img src="images/network_unavailable.svg">
+            <img role="presentation" src="images/network_unavailable.svg">
           </div>
           <div id="closeButtonDiv">
             <cr-button class="action-button" on-click="closeDialog_"
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_manager.js b/chrome/browser/resources/chromeos/switch_access/menu_manager.js
index 94cd0a0..7b61eb07 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_manager.js
+++ b/chrome/browser/resources/chromeos/switch_access/menu_manager.js
@@ -569,8 +569,9 @@
     let id = this.node_.htmlAttributes.id;
 
     // If the selection will close the menu, highlight the back button.
-    if (id === SAConstants.MENU_ID)
+    if (id === SAConstants.MENU_PANEL_ID) {
       id = SAConstants.BACK_ID;
+    }
 
     const enable = !opt_clear;
     this.menuPanel_.setFocusRing(id, enable);
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_panel.html b/chrome/browser/resources/chromeos/switch_access/menu_panel.html
index d47c7bd..fe37dc43 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_panel.html
+++ b/chrome/browser/resources/chromeos/switch_access/menu_panel.html
@@ -14,107 +14,107 @@
 <body>
   <div id="switchaccess_menu_actions"
       aria-label="Switch Access Menu">
-    <button class="action" id="select">
+    <button class="action" id="select" data-position="1">
       <img src="icons/select.svg">
       <p class="i18n" msgid="select"></p>
     </button>
-    <button class="action" id="keyboard">
+    <button class="action" id="keyboard" data-position="2">
       <img src="icons/keyboard.svg">
       <p class="i18n" msgid="open_keyboard"></p>
     </button>
-    <button class="action" id="increment">
+    <button class="action" id="increment" data-position="3">
       <img src="icons/increment.svg">
       <p class="i18n" msgid="increment"></p>
     </button>
-    <button class="action" id="decrement">
+    <button class="action" id="decrement" data-position="4">
       <img src="icons/decrement.svg">
       <p class="i18n" msgid="decrement"></p>
     </button>
-    <button class="action" id="scrollDown">
+    <button class="action" id="scrollDown" data-position="5">
       <img src="icons/scrollDownOrForward.svg">
       <p class="i18n" msgid="scroll_down"></p>
     </button>
-    <button class="action" id="scrollUp">
+    <button class="action" id="scrollUp" data-position="6">
       <img src="icons/scrollUpOrBackward.svg">
       <p class="i18n" msgid="scroll_up"></p>
     </button>
-    <button class="action" id="scrollRight">
+    <button class="action" id="scrollRight" data-position="7">
       <img src="icons/scrollRight.svg">
       <p class="i18n" msgid="scroll_right"></p>
     </button>
-    <button class="action" id="scrollLeft">
+    <button class="action" id="scrollLeft" data-position="8">
       <img src="icons/scrollLeft.svg">
       <p class="i18n" msgid="scroll_left"></p>
     </button>
-    <button class="action" id="scrollForward">
+    <button class="action" id="scrollForward" data-position="9">
       <img src="icons/scrollDownOrForward.svg">
       <p class="i18n" msgid="scroll_forward"></p>
     </button>
-    <button class="action" id="scrollBackward">
+    <button class="action" id="scrollBackward" data-position="10">
       <img src="icons/scrollUpOrBackward.svg">
       <p class="i18n" msgid="scroll_backward"></p>
     </button>
-    <button class="action" id="jumpToBeginningOfText">
+    <button class="action" id="jumpToBeginningOfText" data-position="11">
       <img src="icons/jumpToBeginningOfText.svg">
       <p class="i18n" msgid="jump_to_beginning_of_text"></p>
     </button>
-    <button class="action" id="jumpToEndOfText">
+    <button class="action" id="jumpToEndOfText" data-position="12">
       <img src="icons/jumpToEndOfText.svg">
       <p class="i18n" msgid="jump_to_end_of_text"></p>
     </button>
-    <button class="action" id="moveBackwardOneCharOfText">
+    <button class="action" id="moveBackwardOneCharOfText" data-position="13">
       <img src="icons/moveBackwardOneCharOfText.svg">
       <p class="i18n" msgid="move_backward_one_char_of_text"></p>
     </button>
-    <button class="action" id="moveBackwardOneWordOfText">
+    <button class="action" id="moveBackwardOneWordOfText" data-position="14">
       <img src="icons/moveBackwardOneWordOfText.svg">
       <p class="i18n" msgid="move_backward_one_word_of_text"></p>
     </button>
-    <button class="action" id="moveDownOneLineOfText">
+    <button class="action" id="moveDownOneLineOfText" data-position="15">
       <img src="icons/moveDownOneLineOfText.svg">
       <p class="i18n" msgid="move_down_one_line_of_text"></p>
     </button>
-    <button class="action" id="moveForwardOneCharOfText">
+    <button class="action" id="moveForwardOneCharOfText" data-position="16">
       <img src="icons/moveForwardOneCharOfText.svg">
       <p class="i18n" msgid="move_forward_one_char_of_text"></p>
     </button>
-    <button class="action" id="moveForwardOneWordOfText">
+    <button class="action" id="moveForwardOneWordOfText" data-position="17">
       <img src="icons/moveForwardOneWordOfText.svg">
       <p class="i18n" msgid="move_forward_one_word_of_text"></p>
     </button>
-    <button class="action" id="moveUpOneLineOfText">
+    <button class="action" id="moveUpOneLineOfText" data-position="18">
       <img src="icons/moveUpOneLineOfText.svg">
       <p class="i18n" msgid="move_up_one_line_of_text"></p>
     </button>
-    <button class="action" id="selectStart">
+    <button class="action" id="selectStart" data-position="19">
       <img src="icons/textSelectionStart.svg">
       <p class="i18n" msgid="selection_start"></p>
     </button>
-    <button class="action" id="selectEnd">
+    <button class="action" id="selectEnd" data-position="20">
       <img src="icons/textSelectionEnd.svg">
       <p class="i18n" msgid="selection_end"></p>
     </button>
-    <button class="action" id="cut">
+    <button class="action" id="cut" data-position="21">
       <img src="icons/cut.svg">
       <p class="i18n" msgid="cut"></p>
     </button>
-    <button class="action" id="copy">
+    <button class="action" id="copy" data-position="22">
       <img src="icons/copy.svg">
       <p class="i18n" msgid="copy"></p>
     </button>
-    <button class="action" id="paste">
+    <button class="action" id="paste" data-position="23">
       <img src="icons/paste.svg">
       <p class="i18n" msgid="paste"></p>
     </button>
-    <button class="action" id="dictation">
+    <button class="action" id="dictation" data-position="24">
       <img src="icons/dictation.svg">
       <p class="i18n" msgid="dictation"></p>
     </button>
-    <button class="action" id="showContextMenu">
+    <button class="action" id="showContextMenu" data-position="25">
       <img src="icons/showContextMenu.svg">
       <p class="i18n" msgid="show_context_menu"></p>
     </button>
-    <button class="action" id="settings">
+    <button class="action" id="settings" data-position="26">
       <img src="icons/settings.svg">
       <p class="i18n" msgid="settings_action"></p>
     </button>
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_panel.js b/chrome/browser/resources/chromeos/switch_access/menu_panel.js
index fd3f08d5..2628765 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_panel.js
+++ b/chrome/browser/resources/chromeos/switch_access/menu_panel.js
@@ -19,15 +19,30 @@
      * @private {SwitchAccessInterface}
      */
     this.switchAccess_;
+
+    /**
+     * Reference to the menu panel element.
+     * @private {Element}
+     */
+    this.panel_;
+
+    /**
+     * ID of the current menu being shown in the menu panel.
+     * @private {?SAConstants.MenuId}
+     */
+    this.currentMenuId_;
   }
 
   /**
    * Initialize the panel and buttons.
    */
   init() {
-    const div = document.getElementById(SAConstants.MENU_ID);
-    for (const button of div.children)
+    this.panel_ = document.getElementById(SAConstants.MENU_PANEL_ID);
+
+    const buttons = document.getElementsByTagName('button');
+    for (const button of buttons) {
       this.setupButton_(button);
+    }
 
     const background = chrome.extension.getBackgroundPage();
     if (background.document.readyState === 'complete')
@@ -77,7 +92,7 @@
    * @param {!Array<string>} actions
    */
   setActions(actions) {
-    const div = document.getElementById(SAConstants.MENU_ID);
+    const div = document.getElementById(SAConstants.MENU_PANEL_ID);
     for (const button of div.children)
       button.hidden = !actions.includes(button.id);
 
@@ -85,6 +100,58 @@
   }
 
   /**
+   * Sets the actions in the menu panel to the actions in |actions| from
+   * the menu with the given |menuId|.
+   * TODO(sophyang): Replace setActions() with this function once
+   * submenus are implemented.
+   * @param {!Array<string>} actions
+   * @param {!SAConstants.MenuId} menuId
+   * @public
+   */
+  setActionsFromMenu(actions, menuId) {
+    const menu = document.getElementById(menuId);
+    const menuButtons = Array.from(menu.children);
+
+    // Add the menu to the panel if it is not already being shown.
+    if (menuId !== this.currentMenuId_) {
+      this.panel_.clear();
+      this.panel_.appendChild(menu);
+    }
+
+    // Hide menu actions not applicable to the current node.
+    for (const button of menuButtons) {
+      button.hidden = !actions.includes(button.id);
+    }
+
+    this.currentMenuId_ = menuId;
+
+    this.setHeight_(actions.length);
+  }
+
+  /**
+   * Clears the current menu from the panel.
+   * @public
+   */
+  clear() {
+    if (this.currentMenuId_) {
+      const menu = document.getElementById(this.currentMenuId_);
+      document.body.appendChild(menu);
+
+      this.currentMenuId_ = null;
+    }
+  }
+
+  /**
+   * Get the id of the current menu being shown in the panel. A null
+   * id indicates that no menu is currently being shown in the panel.
+   * @return {?SAConstants.MenuId}
+   * @public
+   */
+  currentMenuId() {
+    return this.currentMenuId_;
+  }
+
+  /**
    * Either adds or removes the class |className| for the element with the given
    * |id|.
    * @param {string} id
@@ -125,7 +192,7 @@
     }
 
     const height = rowHeight * numRows;
-    document.getElementById(SAConstants.MENU_ID).style.height = height + 'px';
+    this.panel_.style.height = height + 'px';
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_panel_interface.js b/chrome/browser/resources/chromeos/switch_access/menu_panel_interface.js
index c2d5fa28..b8a2a86 100644
--- a/chrome/browser/resources/chromeos/switch_access/menu_panel_interface.js
+++ b/chrome/browser/resources/chromeos/switch_access/menu_panel_interface.js
@@ -29,6 +29,18 @@
   setActions(actions) {}
 
   /**
+   * Clears the current menu from the panel.
+   */
+  clear() {}
+
+  /**
+   * Get the id of the current menu being shown in the panel. A null
+   * id indicates that no menu is currently being shown in the panel.
+   * @return {?SAConstants.MenuId}
+   */
+  currentMenuId() {}
+
+  /**
    * Tells the menu panel to try to connect to the background page.
    */
   connectToBackground() {}
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
index 185ff7a..22ed574d 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
@@ -11,7 +11,19 @@
  * @type {string}
  * @const
  */
-SAConstants.MENU_ID = 'switchaccess_menu_actions';
+SAConstants.MENU_PANEL_ID = 'switchaccess_menu_actions';
+
+/**
+ * IDs of menus that can appear in the menu panel.
+ * This must be kept in sync with the div ID of each menu
+ * in menu_panel.html.
+ * @enum {string}
+ * @const
+ */
+SAConstants.MenuId = {
+  MAIN: 'main_menu',
+  TEXT_NAVIGATION: 'text_navigation_menu'
+};
 
 /**
  * The ID of the back button.
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
index a17d2c0..8fd970d 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
@@ -169,7 +169,8 @@
    * @param {!chrome.automation.AutomationNode} node
    * @return {boolean}
    */
-  isSwitchAccessMenu: (node) => node.htmlAttributes.id === SAConstants.MENU_ID,
+  isSwitchAccessMenu: (node) =>
+      node.htmlAttributes.id === SAConstants.MENU_PANEL_ID,
 
   /**
    * Returns a Restrictions object ready to be passed to AutomationTreeWalker.
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 76e7f42..111939a8 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -2238,10 +2238,8 @@
     const tile = customize.createTileWithoutTitle(
         id, imageUrl, dataset, customize.colorTileInteraction,
         customize.tileOnKeyDownInteraction);
-    const label = configData.translatedStrings.colorLabelPrefix + ' ' +
-        colorArrayToHex(colorsColl[i].color);
-    tile.firstElementChild.setAttribute('aria-label', label);
-    tile.firstElementChild.setAttribute('title', label);
+    tile.firstElementChild.setAttribute('aria-label', colorsColl[i].label);
+    tile.firstElementChild.setAttribute('title', colorsColl[i].label);
 
     $(customize.IDS.COLORS_MENU).appendChild(tile);
   }
diff --git a/chrome/browser/resources/local_ntp/externs.js b/chrome/browser/resources/local_ntp/externs.js
index 828895a8..6f8042f 100644
--- a/chrome/browser/resources/local_ntp/externs.js
+++ b/chrome/browser/resources/local_ntp/externs.js
@@ -372,7 +372,6 @@
 configData.translatedStrings.backLabel;
 configData.translatedStrings.backgroundsUnavailable;
 configData.translatedStrings.clickToViewDoodle;
-configData.translatedStrings.colorLabelPrefix;
 configData.translatedStrings.connectionError;
 configData.translatedStrings.connectionErrorNoPeriod;
 configData.translatedStrings.copyLink;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 5b617d0..def03ea 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -1762,6 +1762,13 @@
   width: 50%;
 }
 
+html[dir=rtl] #left-semicircle {
+  border-bottom-left-radius: 0;
+  border-bottom-right-radius: var(--tile-size);
+  border-top-left-radius: 0;
+  border-top-right-radius: var(--tile-size);
+}
+
 #refresh-daily-wrapper {
   display: none;
   margin-inline-start: auto;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 0622671..8d5565e 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -392,9 +392,7 @@
       // is selected doesn't look good.
       const localImageFileName = 'background.jpg';
       if (!configData.richerPicker &&
-          imageWithOverlay.includes(localImageFileName) &&
-          !$(IDS.CUSTOM_BG)
-               .style.backgroundImage.includes(localImageFileName)) {
+          imageWithOverlay.includes(localImageFileName)) {
         customize.closeCustomizationDialog();
       }
       // |image| and |imageWithOverlay| use the same url as their source.
@@ -413,6 +411,7 @@
     }
   } else {
     $(IDS.CUSTOM_BG).style.opacity = '0';
+    $(IDS.CUSTOM_BG).style.backgroundImage = '';
     customize.clearAttribution();
   }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
index 10a96dd..bf15f4f 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -56,7 +56,7 @@
         font-weight: 500;
         margin-inline-end: 2px;
         min-height: 32px;
-        padding-inline-start: 24px;
+        padding-inline-start: 20px;
         pointer-events: none;
       }
 
@@ -75,7 +75,7 @@
 
       iron-icon {
         --iron-icon-fill-color: var(--menu-icon-color);
-        margin-inline-end: 24px;
+        margin-inline-end: 16px;
         pointer-events: none;
         vertical-align: top;
       }
@@ -84,7 +84,6 @@
         fill: var(--menu-link-color);
       }
 
-      /* TODO(crbug.com/950007): Finalize "Advanced" button style. */
       #advancedButton {
         --ink-color: var(--menu-text-color);
         align-items: center;
@@ -99,7 +98,7 @@
         margin-inline-end: 2px;
         margin-top: 8px;
         padding-inline-end: 0;
-        padding-inline-start: 24px;
+        padding-inline-start: 20px;
         text-transform: none;
       }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn
index b098e77..058863d 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn
@@ -16,10 +16,10 @@
     "../..:page_visibility",
     "../../prefs",
     "../os_settings_main:os_settings_main",
+    "../os_toolbar",
     "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/cr_elements/cr_drawer:cr_drawer",
-    "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar",
     "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field",
     "//ui/webui/resources/cr_elements/policy:cr_policy_indicator_behavior",
     "//ui/webui/resources/js:find_shortcut_behavior",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
index ca52ee43..92967db 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
@@ -4,7 +4,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_drawer/cr_drawer.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_page_host_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/find_shortcut_behavior.html">
@@ -12,6 +11,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="../os_settings_menu/os_settings_menu.html">
 <link rel="import" href="../os_settings_main/os_settings_main.html">
+<link rel="import" href="../os_toolbar/os_toolbar.html">
 <link rel="import" href="../../global_scroll_target_behavior.html">
 <link rel="import" href="../../i18n_setup.html">
 <link rel="import" href="../../icons.html">
@@ -37,16 +37,13 @@
             var(--cr-centered-card-width-percentage));
       }
 
-      cr-toolbar {
+      os-toolbar {
         @apply --layout-center;
         /* TODO(hsuregan): update for dark mode when needed. */
         background-color: white;
         color: var(--cr-secondary-text-color);
         min-height: 56px;
         z-index: 2;
-        --cr-toolbar-header-font-weight: 500;
-        --cr-toolbar-left-spacer-width: var(--settings-menu-width);
-        --cr-toolbar-center-basis: var(--settings-main-basis);
         --cr-toolbar-search-field-background: var(--google-grey-refresh-100);
         --cr-toolbar-search-field-border-radius: 4px;
         --cr-toolbar-search-field-input-color: var(--google-grey-refresh-700);
@@ -107,18 +104,14 @@
       }
     </style>
     <settings-prefs id="prefs" prefs="{{prefs}}"></settings-prefs>
-    <cr-toolbar page-name="$i18n{settings}"
-        clear-label="$i18n{clearSearch}"
-        search-prompt="$i18n{searchPrompt}"
-        on-cr-toolbar-menu-tap="onMenuButtonTap_"
+    <os-toolbar on-os-toolbar-menu-tap="onMenuButtonTap_"
         spinner-active="[[toolbarSpinnerActive_]]"
-        menu-label="$i18n{menuButtonLabel}"
         on-search-changed="onSearchChanged_"
         role="banner"
         narrow="{{isNarrow}}"
         narrow-threshold="980"
         show-menu="[[isNarrow]]">
-    </cr-toolbar>
+    </os-toolbar>
     <cr-drawer id="drawer" on-close="onMenuClose_" heading="$i18n{settings}"
         align="$i18n{textdirection}">
       <div class="drawer-content">
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
index b5215a6b..122df02 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
@@ -58,7 +58,7 @@
 
     /**
      * Whether settings is in the narrow state (side nav hidden). Controlled by
-     * a binding in the cr-toolbar element.
+     * a binding in the os-toolbar element.
      */
     isNarrow: {
       type: Boolean,
@@ -244,7 +244,7 @@
 
     this.lastSearchQuery_ = urlSearchQuery;
 
-    const toolbar = /** @type {!CrToolbarElement} */ (this.$$('cr-toolbar'));
+    const toolbar = /** @type {!OsToolbarElement} */ (this.$$('os-toolbar'));
     const searchField =
         /** @type {CrToolbarSearchFieldElement} */ (toolbar.getSearchField());
 
@@ -264,13 +264,13 @@
     if (modalContextOpen) {
       return false;
     }
-    this.$$('cr-toolbar').getSearchField().showAndFocus();
+    this.$$('os-toolbar').getSearchField().showAndFocus();
     return true;
   },
 
   // Override FindShortcutBehavior methods.
   searchInputHasFocus: function() {
-    return this.$$('cr-toolbar').getSearchField().isSearchFocused();
+    return this.$$('os-toolbar').getSearchField().isSearchFocused();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn
new file mode 100644
index 0000000..3ac49b9
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_toolbar/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":os_toolbar",
+  ]
+}
+
+js_library("os_toolbar") {
+  deps = [
+    "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar_search_field",
+  ]
+  externs_list = [ "$externs_path/web_animations.js" ]
+}
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html
new file mode 100644
index 0000000..2313c6e
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.html
@@ -0,0 +1,120 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html">
+<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html">
+
+<dom-module id="os-toolbar">
+  <template>
+    <style include="cr-icons cr-hidden-style">
+      :host {
+        align-items: center;
+        background-color: var(--google-blue-700);
+        color: #fff;
+        display: flex;
+        height: var(--cr-toolbar-height);
+      }
+
+      h1 {
+        flex: 1;
+        font-size: 123%;
+        font-weight: 500;
+        letter-spacing: .25px;
+        line-height: normal;
+        margin-inline-start: 8px;
+        padding-inline-end: 12px;
+      }
+
+      #leftContent {
+        position: relative;
+        transition: opacity 100ms;
+      }
+
+      #leftSpacer {
+        align-items: center;
+        box-sizing: border-box;
+        display: flex;
+        /* 8px to match #rightSpacer + 6px to align with icons in menus. */
+        padding-inline-start: 14px;
+        width: var(--settings-menu-width);
+      }
+
+      cr-icon-button {
+        --cr-icon-button-color: currentColor;
+        --cr-icon-button-size: 32px;
+        min-width: 32px;
+      }
+
+      #centeredContent {
+        display: flex;
+        flex: 1 1 0;
+        justify-content: center;
+      }
+
+      #rightSpacer {
+        padding-inline-end: 8px;
+      }
+
+      :host([narrow]) #centeredContent {
+        justify-content: flex-end;
+      }
+
+      :host([has-overlay]) {
+        transition: visibility var(--cr-toolbar-overlay-animation-duration);
+        visibility: hidden;
+      }
+
+      :host([narrow][showing-search_]) #leftContent {
+        opacity: 0;
+        position: absolute;
+      }
+
+      :host(:not([narrow])) #leftContent {
+        flex: 1 1 0;
+      }
+
+      :host(:not([narrow])) #centeredContent {
+        flex-basis: var(--settings-main-basis);
+      }
+
+      :host(:not([narrow])) #rightContent {
+        flex: 1 1 0;
+        text-align: end;
+      }
+    </style>
+    <div id="leftContent">
+      <div id="leftSpacer">
+        <template is="dom-if" if="[[showMenu]]">
+          <cr-icon-button id="menuButton" class="no-overlap"
+              iron-icon="cr20:menu" on-click="onMenuTap_"
+              aria-label="$i18n{menuButtonLabel}"
+              title="$i18n{menuButtonLabel}">
+          </cr-icon-button>
+        </template>
+        <h1>$i18n{settings}</h1>
+      </div>
+    </div>
+
+    <div id="centeredContent" hidden$="[[!showSearch]]">
+      <cr-toolbar-search-field id="search" narrow="[[narrow]]"
+          label="$i18n{searchPrompt}" clear-label="$i18n{clearSearch}"
+          spinner-active="[[spinnerActive]]"
+          showing-search="{{showingSearch_}}">
+      </cr-toolbar-search-field>
+      <iron-media-query query="(max-width: [[narrowThreshold]]px)"
+          query-matches="{{narrow}}">
+      </iron-media-query>
+    </div>
+
+    <div id="rightContent">
+      <div id="rightSpacer">
+        <slot></slot>
+      </div>
+    </div>
+  </template>
+  <script src="os_toolbar.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js
new file mode 100644
index 0000000..17b4d63
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_toolbar/os_toolbar.js
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Polymer({
+  // Not "toolbar" because element names must contain a hyphen.
+  is: 'os-toolbar',
+
+  properties: {
+    // Value is proxied through to cr-toolbar-search-field. When true,
+    // the search field will show a processing spinner.
+    spinnerActive: Boolean,
+
+    // Controls whether the menu button is shown at the start of the menu.
+    showMenu: {type: Boolean, value: false},
+
+    // Controls whether the search field is shown.
+    showSearch: {type: Boolean, value: true},
+
+    // True when the toolbar is displaying in narrow mode.
+    narrow: {
+      type: Boolean,
+      reflectToAttribute: true,
+      readonly: true,
+      notify: true,
+    },
+
+    /**
+     * The threshold at which the toolbar will change from normal to narrow
+     * mode, in px.
+     */
+    narrowThreshold: {
+      type: Number,
+      value: 900,
+    },
+
+    /** @private */
+    showingSearch_: {
+      type: Boolean,
+      reflectToAttribute: true,
+    },
+  },
+
+  /** @return {!CrToolbarSearchFieldElement} */
+  getSearchField: function() {
+    return this.$.search;
+  },
+
+  /** @private */
+  onMenuTap_: function() {
+    this.fire('os-toolbar-menu-tap');
+  },
+});
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 73d0a5fc..c5e635b 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -527,6 +527,12 @@
       <structure name="IDR_OS_SETTINGS_MEDIA_PICKER_JS"
                  file="site_settings/media_picker.js"
                  type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_OS_TOOLBAR_JS"
+                 file="chromeos/os_toolbar/os_toolbar.js"
+                 type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_OS_TOOLBAR_HTML"
+                 file="chromeos/os_toolbar/os_toolbar.html"
+                 type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_PEOPLE_PAGE_HTML"
                  file="chromeos/os_people_page/os_people_page.html"
                  type="chrome_html"
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 4723d22..6160fc5 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -83,6 +83,8 @@
       "safe_browsing_navigation_throttle.h",
       "safe_browsing_service.cc",
       "safe_browsing_service.h",
+      "safe_browsing_subresource_tab_helper.cc",
+      "safe_browsing_subresource_tab_helper.h",
       "services_delegate.h",
       "telemetry/telemetry_service.cc",
       "telemetry/telemetry_service.h",
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index b3f9faf..22ddc67 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -189,8 +189,7 @@
 }
 
 void SafeBrowsingBlockingPage::OnInterstitialClosing() {
-  if (base::FeatureList::IsEnabled(safe_browsing::kCommittedSBInterstitials) &&
-      IsMainPageLoadBlocked(unsafe_resources())) {
+  if (base::FeatureList::IsEnabled(safe_browsing::kCommittedSBInterstitials)) {
     // With committed interstitials OnProceed and OnDontProceed don't get
     // called, so call FinishThreatDetails from here.
     FinishThreatDetails(
@@ -292,7 +291,6 @@
   auto interstitial_command =
       static_cast<security_interstitials::SecurityInterstitialCommand>(command);
   if (base::FeatureList::IsEnabled(safe_browsing::kCommittedSBInterstitials) &&
-      IsMainPageLoadBlocked(unsafe_resources()) &&
       interstitial_command ==
           security_interstitials::SecurityInterstitialCommand::CMD_PROCEED) {
     // With committed interstitials, OnProceed() doesn't get called, so handle
diff --git a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc
new file mode 100644
index 0000000..529b8720
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "net/base/net_errors.h"
+
+namespace safe_browsing {
+
+SafeBrowsingSubresourceTabHelper::~SafeBrowsingSubresourceTabHelper() {}
+
+void SafeBrowsingSubresourceTabHelper::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (navigation_handle->GetNetErrorCode() == net::ERR_BLOCKED_BY_CLIENT) {
+    safe_browsing::SafeBrowsingService* service =
+        g_browser_process->safe_browsing_service();
+    if (!service)
+      return;
+    security_interstitials::UnsafeResource resource;
+    scoped_refptr<safe_browsing::SafeBrowsingUIManager> manager =
+        service->ui_manager();
+    if (manager->PopUnsafeResourceForURL(navigation_handle->GetURL(),
+                                         &resource)) {
+      safe_browsing::SafeBrowsingBlockingPage* blocking_page =
+          safe_browsing::SafeBrowsingBlockingPage::CreateBlockingPage(
+              manager.get(), navigation_handle->GetWebContents(),
+              navigation_handle->GetURL(), resource);
+      security_interstitials::SecurityInterstitialTabHelper::
+          AssociateBlockingPage(navigation_handle->GetWebContents(),
+                                navigation_handle->GetNavigationId(),
+                                base::WrapUnique(blocking_page));
+    }
+  }
+}
+
+SafeBrowsingSubresourceTabHelper::SafeBrowsingSubresourceTabHelper(
+    content::WebContents* web_contents)
+    : WebContentsObserver(web_contents) {}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(SafeBrowsingSubresourceTabHelper)
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h
new file mode 100644
index 0000000..e06683fe0
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SUBRESOURCE_TAB_HELPER_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SUBRESOURCE_TAB_HELPER_H_
+
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class NavigationHandle;
+class WebContents;
+}  // namespace content
+
+namespace safe_browsing {
+
+class SafeBrowsingSubresourceTabHelper
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<SafeBrowsingSubresourceTabHelper> {
+ public:
+  ~SafeBrowsingSubresourceTabHelper() override;
+
+  // WebContentsObserver::
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+ private:
+  explicit SafeBrowsingSubresourceTabHelper(content::WebContents* web_contents);
+  friend class content::WebContentsUserData<SafeBrowsingSubresourceTabHelper>;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingSubresourceTabHelper);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SUBRESOURCE_TAB_HELPER_H_
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc
index f6f9d45..bde0f37 100644
--- a/chrome/browser/safe_browsing/ui_manager.cc
+++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -26,6 +27,7 @@
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/ping_manager.h"
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
@@ -158,6 +160,28 @@
   observer_list_.RemoveObserver(observer);
 }
 
+void SafeBrowsingUIManager::DisplayBlockingPage(
+    const UnsafeResource& resource) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  BaseUIManager::DisplayBlockingPage(resource);
+  if (!resource.IsMainPageLoadBlocked() && !IsWhitelisted(resource) &&
+      SafeBrowsingInterstitialsAreCommittedNavigations()) {
+    content::WebContents* contents = resource.web_contents_getter.Run();
+    content::NavigationEntry* entry = resource.GetNavigationEntryForResource();
+    // entry can be null if we are on a brand new tab, and a resource is added
+    // via javascript without a navigation.
+    GURL blocked_url = entry ? entry->GetURL() : resource.url;
+    SafeBrowsingBlockingPage* blocking_page =
+        SafeBrowsingBlockingPage::CreateBlockingPage(this, contents,
+                                                     blocked_url, resource);
+    SafeBrowsingSubresourceTabHelper::CreateForWebContents(contents);
+    contents->GetController().LoadErrorPage(
+        contents->GetMainFrame(), blocked_url, blocking_page->GetHTMLContents(),
+        net::ERR_BLOCKED_BY_CLIENT);
+    delete blocking_page;
+  }
+}
+
 const std::string SafeBrowsingUIManager::app_locale() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return g_browser_process->GetApplicationLocale();
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h
index 87b2d58..a0ce3798 100644
--- a/chrome/browser/safe_browsing/ui_manager.h
+++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -89,6 +89,8 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* remove);
 
+  void DisplayBlockingPage(const UnsafeResource& resource) override;
+
   const std::string app_locale() const override;
   history::HistoryService* history_service(
       content::WebContents* web_contents) override;
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 7f35f4f..83a40e8 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -295,10 +295,6 @@
               IDS_NEW_TAB_VOICE_OTHER_ERROR);
     AddString(translated_strings.get(), "voiceCloseTooltip",
               IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP);
-
-    // Colors menu
-    AddString(translated_strings.get(), "colorLabelPrefix",
-              IDS_NTP_CUSTOMIZE_COLOR_LABEL_PREFIX);
   }
 
   return translated_strings;
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index c42ee3a..1d63283 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -54,23 +54,17 @@
       return gfx::kGoogleGrey900;
     case ThemeProperties::COLOR_BOOKMARK_TEXT:
     case ThemeProperties::COLOR_TAB_TEXT:
-    case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_ACTIVE:
     case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON:
       return gfx::kGoogleGrey100;
     case ThemeProperties::COLOR_NTP_TEXT:
       return gfx::kGoogleGrey200;
     case ThemeProperties::COLOR_BACKGROUND_TAB_TEXT:
     case ThemeProperties::COLOR_BACKGROUND_TAB_TEXT_INACTIVE:
-    case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_INACTIVE:
     case ThemeProperties::COLOR_TAB_ALERT_AUDIO:
     case ThemeProperties::COLOR_TAB_ALERT_CAPTURING:
     case ThemeProperties::COLOR_TAB_PIP_PLAYING:
     case ThemeProperties::COLOR_TAB_ALERT_RECORDING:
       return gfx::kGoogleGrey400;
-    case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER:
-      return gfx::kGoogleGrey700;
-    case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED:
-      return gfx::kGoogleGrey600;
     case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
       return SkColorSetRGB(0x28, 0x28, 0x28);
     case ThemeProperties::COLOR_NTP_LINK:
@@ -246,14 +240,8 @@
       return gfx::kPlaceholderColor;
 
     // Properties not stored in theme pack.
-    case COLOR_TAB_CLOSE_BUTTON_ACTIVE:
-    case COLOR_TAB_CLOSE_BUTTON_INACTIVE:
     case COLOR_TAB_ALERT_AUDIO:
       return gfx::kChromeIconGrey;
-    case COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER:
-      return gfx::kGoogleGrey200;
-    case COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED:
-      return gfx::kGoogleGrey300;
     case COLOR_TAB_ALERT_RECORDING:
       return gfx::kGoogleRed600;
     case COLOR_TAB_ALERT_CAPTURING:
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h
index 11d835b..18e69af 100644
--- a/chrome/browser/themes/theme_properties.h
+++ b/chrome/browser/themes/theme_properties.h
@@ -124,12 +124,6 @@
     COLOR_TAB_THROBBER_SPINNING,
     COLOR_TAB_THROBBER_WAITING,
 
-    // Colors for the tab close button inons.
-    COLOR_TAB_CLOSE_BUTTON_ACTIVE,
-    COLOR_TAB_CLOSE_BUTTON_INACTIVE,
-    COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER,
-    COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED,
-
     // The colors used by the various alert indicator icons in the tab.
     COLOR_TAB_ALERT_AUDIO,
     COLOR_TAB_ALERT_RECORDING,
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc b/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
index 1ef494aa..ed4859c 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
@@ -7,8 +7,6 @@
 #include "ash/public/cpp/app_menu_constants.h"
 #include "base/bind_helpers.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
-#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
-#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/grit/generated_resources.h"
 
@@ -21,24 +19,7 @@
 CrostiniAppContextMenu::~CrostiniAppContextMenu() = default;
 
 bool CrostiniAppContextMenu::IsUninstallable() const {
-  if (!crostini::IsCrostiniEnabled(profile())) {
-    return false;
-  }
-  if (app_id() == crostini::kCrostiniTerminalId &&
-      !crostini::CrostiniManager::GetForProfile(profile())
-           ->GetInstallerViewStatus()) {
-    // Crostini should not be uninstalled if the installer is still running.
-    return true;
-  }
-
-  crostini::CrostiniRegistryService* registry_service =
-      crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
-  base::Optional<crostini::CrostiniRegistryService::Registration> registration =
-      registry_service->GetRegistration(app_id());
-  if (registration) {
-    return registration->CanUninstall();
-  }
-  return false;
+  return crostini::IsUninstallable(profile(), app_id());
 }
 
 // TODO(timloh): Add support for "App Info" and possibly actions defined in
diff --git a/chrome/browser/ui/apps/app_info_dialog.h b/chrome/browser/ui/apps/app_info_dialog.h
index 8bf40367..abe2ef4 100644
--- a/chrome/browser/ui/apps/app_info_dialog.h
+++ b/chrome/browser/ui/apps/app_info_dialog.h
@@ -31,6 +31,7 @@
   FROM_APP_LIST,         // Launched from the app list context menu (ChromeOS).
   FROM_EXTENSIONS_PAGE,  // Launched from the chrome://extensions page.
   FROM_APPS_PAGE,        // Launched from chrome://apps context menu.
+  FROM_SHELF,            // Launched from chrome shelf.
   NUM_LAUNCH_SOURCES,
 };
 
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
index d8f3684..5cad7412 100644
--- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
@@ -11,10 +11,14 @@
 #include "ash/public/cpp/shelf_item.h"
 #include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_dialog.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_shelf_id.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 
 ArcLauncherContextMenu::ArcLauncherContextMenu(
@@ -36,6 +40,14 @@
     app_shortcuts_menu_builder_->ExecuteCommand(command_id);
     return;
   }
+  if (command_id == ash::SHOW_APP_INFO) {
+    ShowPackageInfo();
+    return;
+  }
+  if (command_id == ash::UNINSTALL) {
+    arc::ShowArcAppUninstallDialog(controller()->profile(), item().id.app_id);
+    return;
+  }
 
   LauncherContextMenu::ExecuteCommand(command_id, event_flags);
 }
@@ -67,6 +79,14 @@
   if (!app_id.has_shelf_group_id() && app_info->launchable)
     AddPinMenu(menu_model.get());
 
+  if (!app_info->sticky) {
+    AddContextMenuOption(menu_model.get(), ash::UNINSTALL,
+                         IDS_APP_LIST_UNINSTALL_ITEM);
+  }
+
+  AddContextMenuOption(menu_model.get(), ash::SHOW_APP_INFO,
+                       IDS_APP_CONTEXT_MENU_SHOW_INFO);
+
   if (app_is_open) {
     AddContextMenuOption(menu_model.get(), ash::MENU_CLOSE,
                          IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
@@ -80,3 +100,22 @@
   app_shortcuts_menu_builder_->BuildMenu(
       app_info->package_name, std::move(menu_model), std::move(callback));
 }
+
+void ArcLauncherContextMenu::ShowPackageInfo() {
+  const ArcAppListPrefs* arc_prefs =
+      ArcAppListPrefs::Get(controller()->profile());
+  DCHECK(arc_prefs);
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      arc_prefs->GetApp(item().id.app_id);
+  if (!app_info) {
+    VLOG(2) << "Requesting AppInfo for package that does not exist: "
+            << item().id.app_id << ".";
+    return;
+  }
+  if (base::FeatureList::IsEnabled(features::kAppManagement)) {
+    chrome::ShowAppManagementPage(controller()->profile(), item().id.app_id);
+    return;
+  }
+  arc::ShowPackageInfo(app_info->package_name,
+                       arc::mojom::ShowPackageInfoPage::MAIN, display_id());
+}
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
index 6cb4c23e..d54d4f8 100644
--- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
@@ -27,6 +27,9 @@
   void ExecuteCommand(int command_id, int event_flags) override;
 
  private:
+  // Launches App Info UI for ARC apps.
+  void ShowPackageInfo();
+
   void BuildMenu(std::unique_ptr<ui::SimpleMenuModel> menu_model,
                  GetMenuModelCallback callback);
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index c32f276e..995860b5 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -18,6 +18,7 @@
 #include "ash/public/cpp/window_animation_types.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/pattern.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -36,6 +37,7 @@
 #include "chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/md_icon_normalizer.h"
+#include "chrome/browser/ui/apps/app_info_dialog.h"
 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
@@ -61,9 +63,12 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
@@ -79,6 +84,7 @@
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_manager_connection.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/aura/client/aura_constants.h"
@@ -119,6 +125,13 @@
   return app_id_opt.value_or("");
 }
 
+const extensions::Extension* GetExtension(Profile* profile,
+                                          const std::string& extension_id) {
+  const extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile);
+  return registry->GetInstalledExtension(extension_id);
+}
+
 }  // namespace
 
 // A class to get events from ChromeOS when a user gets changed or added.
@@ -770,6 +783,41 @@
   return nullptr;
 }
 
+bool ChromeLauncherController::CanDoShowAppInfoFlow() {
+  return CanShowAppInfoDialog();
+}
+
+void ChromeLauncherController::DoShowAppInfoFlow(
+    Profile* profile,
+    const std::string& extension_id) {
+  DCHECK(CanDoShowAppInfoFlow());
+
+  const extensions::Extension* extension = GetExtension(profile, extension_id);
+  if (!extension)
+    return;
+
+  if (base::FeatureList::IsEnabled(features::kAppManagement)) {
+    chrome::ShowAppManagementPage(profile, extension_id);
+    return;
+  }
+
+  if (extension->is_hosted_app() && extension->from_bookmark()) {
+    chrome::ShowSiteSettings(
+        profile, extensions::AppLaunchInfo::GetFullLaunchURL(extension));
+    return;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
+                            AppInfoLaunchSource::FROM_SHELF,
+                            AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
+
+  ShowAppInfoInNativeDialog(BrowserList::GetInstance()
+                                ->GetLastActive()
+                                ->tab_strip_model()
+                                ->GetActiveWebContents(),
+                            profile, extension, base::Closure());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // LauncherAppUpdater::Delegate:
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 7458ca04..1bea392 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -244,6 +244,13 @@
   bool IsAppPinned(const std::string& app_id);
   void UnpinAppWithID(const std::string& app_id);
 
+  // Whether the controller supports a Show App Info flow.
+  bool CanDoShowAppInfoFlow();
+
+  // Show the dialog with the application's information. Call only if
+  // CanDoShowAppInfoFlow() returns true.
+  void DoShowAppInfoFlow(Profile* profile, const std::string& extension_id);
+
   // LauncherAppUpdater::Delegate:
   void OnAppInstalled(content::BrowserContext* browser_context,
                       const std::string& app_id) override;
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
index 92aec05..f5bd813 100644
--- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
@@ -56,6 +56,10 @@
   std::move(callback).Run(std::move(menu_model));
 }
 
+bool CrostiniShelfContextMenu::IsUninstallable() const {
+  return crostini::IsUninstallable(controller()->profile(), item().id.app_id);
+}
+
 void CrostiniShelfContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   const crostini::CrostiniRegistryService* registry_service =
       crostini::CrostiniRegistryServiceFactory::GetForProfile(
@@ -78,6 +82,11 @@
                          IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM);
   }
 
+  if (IsUninstallable()) {
+    AddContextMenuOption(menu_model, ash::UNINSTALL,
+                         IDS_APP_LIST_UNINSTALL_ITEM);
+  }
+
   if (controller()->IsOpen(item().id)) {
     AddContextMenuOption(menu_model, ash::MENU_CLOSE,
                          IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
index 744e7ca..fdbc13ebf 100644
--- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
@@ -21,6 +21,7 @@
   void ExecuteCommand(int command_id, int event_flags) override;
 
  private:
+  bool IsUninstallable() const;
   void BuildMenu(ui::SimpleMenuModel* menu_model);
 
   DISALLOW_COPY_AND_ASSIGN(CrostiniShelfContextMenu);
diff --git a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
index 4a02829..8e8d921 100644
--- a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/common/context_menu_params.h"
 #include "extensions/browser/extension_prefs.h"
@@ -119,6 +120,10 @@
   ScopedDisplayIdForNewWindows scoped_display(display_id());
 
   switch (static_cast<ash::CommandId>(command_id)) {
+    case ash::SHOW_APP_INFO:
+      controller()->DoShowAppInfoFlow(controller()->profile(),
+                                      item().id.app_id);
+      break;
     case ash::LAUNCH_TYPE_PINNED_TAB:
       SetLaunchType(extensions::LAUNCH_TYPE_PINNED);
       break;
@@ -174,16 +179,20 @@
 
 void ExtensionLauncherContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   Profile* profile = controller()->profile();
+  const std::string app_id = item().id.app_id;
+
   extension_items_.reset(new extensions::ContextMenuMatcher(
       profile, this, menu_model,
       base::BindRepeating(MenuItemHasLauncherContext)));
+  // V1 apps can be started from the menu - but V2 apps and system web apps
+  // should not.
+  bool is_system_web_app = web_app::WebAppProvider::Get(profile)
+                               ->system_web_app_manager()
+                               .IsSystemWebApp(app_id);
+  const bool is_platform_app = controller()->IsPlatformApp(item().id);
+
   if (item().type == ash::TYPE_PINNED_APP || item().type == ash::TYPE_APP) {
-    // V1 apps can be started from the menu - but V2 apps and system web apps
-    // should not.
-    bool is_system_web_app = web_app::WebAppProvider::Get(profile)
-                                 ->system_web_app_manager()
-                                 .IsSystemWebApp(item().id.app_id);
-    if (!controller()->IsPlatformApp(item().id) && !is_system_web_app)
+    if (!is_platform_app && !is_system_web_app)
       CreateOpenNewSubmenu(menu_model);
     AddPinMenu(menu_model);
 
@@ -198,26 +207,31 @@
       AddContextMenuOption(menu_model, ash::MENU_NEW_INCOGNITO_WINDOW,
                            IDS_APP_LIST_NEW_INCOGNITO_WINDOW);
     }
-    if (!BrowserShortcutLauncherItemController::IsListOfActiveBrowserEmpty()) {
+    if (!BrowserShortcutLauncherItemController::IsListOfActiveBrowserEmpty() ||
+        item().type == ash::TYPE_DIALOG || controller()->IsOpen(item().id)) {
       AddContextMenuOption(menu_model, ash::MENU_CLOSE,
                            IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
     }
-  } else if (item().type == ash::TYPE_DIALOG) {
-    AddContextMenuOption(menu_model, ash::MENU_CLOSE,
-                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
-  } else if (controller()->IsOpen(item().id)) {
-    AddContextMenuOption(menu_model, ash::MENU_CLOSE,
-                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
   }
+  if (app_id != extension_misc::kChromeAppId) {
+    AddContextMenuOption(menu_model, ash::UNINSTALL,
+                         is_platform_app ? IDS_APP_LIST_UNINSTALL_ITEM
+                                         : IDS_APP_LIST_EXTENSIONS_UNINSTALL);
+  }
+
+  if (controller()->CanDoShowAppInfoFlow() && !is_system_web_app) {
+    AddContextMenuOption(menu_model, ash::SHOW_APP_INFO,
+                         IDS_APP_CONTEXT_MENU_SHOW_INFO);
+  }
+
   if (item().type == ash::TYPE_PINNED_APP || item().type == ash::TYPE_APP) {
-    const extensions::MenuItem::ExtensionKey app_key(item().id.app_id);
+    const extensions::MenuItem::ExtensionKey app_key(app_id);
     if (!app_key.empty()) {
       int index = 0;
       extension_items_->AppendExtensionItems(app_key, base::string16(), &index,
                                              false);  // is_action_menu
       app_list::AddMenuItemIconsForSystemApps(
-          item().id.app_id, menu_model, menu_model->GetItemCount() - index,
-          index);
+          app_id, menu_model, menu_model->GetItemCount() - index, index);
     }
   }
 }
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 613b14c..76f640a67 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "chrome/browser/ui/app_list/extension_uninstaller.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -27,6 +28,16 @@
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/vector_icons.h"
 
+namespace {
+
+void UninstallApp(Profile* profile, const std::string& app_id) {
+  // ExtensionUninstall deletes itself when done or aborted.
+  ExtensionUninstaller* uninstaller = new ExtensionUninstaller(profile, app_id);
+  uninstaller->Run();
+}
+
+}  // namespace
+
 // static
 std::unique_ptr<LauncherContextMenu> LauncherContextMenu::Create(
     ChromeLauncherController* controller,
@@ -118,6 +129,9 @@
       else
         controller_->PinAppWithID(item_.id.app_id);
       break;
+    case ash::UNINSTALL:
+      UninstallApp(controller_->profile(), item_.id.app_id);
+      break;
     default:
       NOTREACHED();
   }
@@ -151,6 +165,7 @@
     case ash::MENU_OPEN_NEW:
     case ash::MENU_CLOSE:
     case ash::MENU_PIN:
+    case ash::UNINSTALL:
       LauncherContextMenu::ExecuteCommand(command_id, event_flags);
       return true;
     default:
@@ -198,6 +213,10 @@
       return views::kOpenIcon;
     case ash::MENU_CLOSE:
       return views::kCloseIcon;
+    case ash::SHOW_APP_INFO:
+      return views::kInfoIcon;
+    case ash::UNINSTALL:
+      return views::kUninstallIcon;
     case ash::MENU_PIN:
       return controller_->IsPinned(item_.id) ? views::kUnpinIcon
                                              : views::kPinIcon;
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.h b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
index e80e7c25..7ea1f57 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
@@ -8,6 +8,7 @@
 #include "ash/public/cpp/app_menu_constants.h"
 #include "ash/public/cpp/shelf_item.h"
 #include "base/macros.h"
+#include "chrome/browser/ui/app_list/extension_uninstaller.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/gfx/vector_icon_types.h"
 
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
index 7c6535e..4c29aeb 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -217,7 +217,32 @@
   ASSERT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_CLOSE));
 }
 
+// Verifies that "App Info and Uninstall" are shown in context menu for pinned
+// apps.
+TEST_F(LauncherContextMenuTest, GeneralAppContextMenuInfoUninstall) {
+  const int64_t display_id = GetPrimaryDisplay().id();
+  std::unique_ptr<LauncherContextMenu> launcher_context_menu =
+      CreateLauncherContextMenu(ash::TYPE_PINNED_APP, display_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetMenuModel(launcher_context_menu.get());
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
+}
+
+// Verifies that "App Info and Uninstall" are shown in context menu for V1, V2,
+// and ARC apps.
+TEST_F(LauncherContextMenuTest, ArcAppContextMenuInfoUninstall) {
+  const int64_t display_id = GetPrimaryDisplay().id();
+  std::unique_ptr<LauncherContextMenu> launcher_context_menu =
+      CreateLauncherContextMenu(ash::TYPE_APP, display_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetMenuModel(launcher_context_menu.get());
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
+}
+
 // Verifies context menu and app menu items for ARC app.
+// The 0th item is sticky but not the following.
 TEST_F(LauncherContextMenuTest, ArcLauncherMenusCheck) {
   arc_test().app_instance()->SendRefreshAppList(
       std::vector<arc::mojom::AppInfo>(arc_test().fake_apps().begin(),
@@ -244,6 +269,8 @@
   // ARC app is pinned but not running.
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_PIN));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_FALSE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_CLOSE));
 
   // ARC app is running.
@@ -264,6 +291,8 @@
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_PIN));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_CLOSE));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_FALSE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 
   // ARC non-launchable app is running.
   const std::string app_id2 = ArcAppTest::GetAppId(arc_test().fake_apps()[1]);
@@ -290,6 +319,8 @@
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_PIN));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_CLOSE));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 
   // Shelf group context menu.
   std::vector<arc::mojom::ShortcutInfo> shortcuts = arc_test().fake_shortcuts();
@@ -331,6 +362,8 @@
     EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
     EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_PIN));
     EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_CLOSE));
+    EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+    EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 
     menu_list = item_delegate3->GetAppMenuItems(0 /* event_flags */);
     ASSERT_EQ(i + 1, menu_list.size());
@@ -368,6 +401,8 @@
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_PIN));
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_CLOSE));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_FALSE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 }
 
 TEST_F(LauncherContextMenuTest, ArcDeferredLauncherContextMenuItemCheck) {
@@ -405,6 +440,8 @@
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_PIN));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_CLOSE));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_FALSE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 
   item_delegate = model()->GetShelfItemDelegate(shelf_id2);
   ASSERT_TRUE(item_delegate);
@@ -414,6 +451,8 @@
   EXPECT_FALSE(IsItemPresentInMenu(menu.get(), ash::MENU_OPEN_NEW));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_PIN));
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::MENU_CLOSE));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::SHOW_APP_INFO));
+  EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 }
 
 TEST_F(LauncherContextMenuTest, CommandIdsMatchEnumsForHistograms) {
@@ -432,10 +471,10 @@
 }
 
 TEST_F(LauncherContextMenuTest, ArcContextMenuOptions) {
-  // Tests that there are 8 ARC app context menu options. If you're
-  // adding a context menu option ensure that you have added the enum to
-  // tools/metrics/enums.xml and that you haven't modified the order of the
-  // existing enums.
+  // Tests that there are the right number of ARC app context menu options. If
+  // you're adding a context menu option ensure that you have added the enum to
+  // tools/metrics/histograms/enums.xml and that you haven't modified the order
+  // of the existing enums.
   arc_test().app_instance()->SendRefreshAppList(
       std::vector<arc::mojom::AppInfo>(arc_test().fake_apps().begin(),
                                        arc_test().fake_apps().begin() + 1));
@@ -452,8 +491,8 @@
   std::unique_ptr<ui::MenuModel> menu =
       GetContextMenu(item_delegate, primary_id);
 
-  // Test that there are 8 items in an ARC app context menu.
-  EXPECT_EQ(8, menu->GetItemCount());
+  // Test that there are 9 items in an ARC app context menu.
+  EXPECT_EQ(9, menu->GetItemCount());
 }
 
 // Tests that the context menu of internal app  is correct.
@@ -578,6 +617,7 @@
   // care that one is shown.
   EXPECT_TRUE(IsItemEnabledInMenu(menu.get(), ash::CROSTINI_USE_LOW_DENSITY) ||
               IsItemEnabledInMenu(menu.get(), ash::CROSTINI_USE_HIGH_DENSITY));
+  EXPECT_FALSE(IsItemEnabledInMenu(menu.get(), ash::UNINSTALL));
 }
 
 // Confirms the menu items for unregistered crostini apps (i.e. apps that do not
diff --git a/chrome/browser/ui/tabs/tab_style.h b/chrome/browser/ui/tabs/tab_style.h
index ed9b943..95fd4b9 100644
--- a/chrome/browser/ui/tabs/tab_style.h
+++ b/chrome/browser/ui/tabs/tab_style.h
@@ -76,13 +76,8 @@
 
   // Colors for various parts of the tab derived by TabStyle.
   struct TabColors {
+    SkColor foreground_color;
     SkColor background_color;
-    SkColor title_color;
-    SkColor button_icon_idle_color;
-    SkColor button_icon_hovered_color;
-    SkColor button_icon_pressed_color;
-    SkColor button_background_hovered_color;
-    SkColor button_background_pressed_color;
   };
 
   virtual ~TabStyle();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
index 5ba34ce..01906ca 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
@@ -177,10 +177,10 @@
   }
 
   use_deemphasized_font_ = deemphasize;
-  render_text_.reset();
   render_text_ = CreateRenderText(text);
   UpdateLineHeight();
   SetPreferredSize(CalculatePreferredSize());
+  SchedulePaint();
 }
 
 void OmniboxTextView::SetText(const base::string16& text,
@@ -197,6 +197,7 @@
       std::make_unique<ACMatchClassifications>(classifications);
   render_text_ = CreateRenderText(text);
 
+  // ReapplyStyling will update the preferred size and request a repaint.
   ReapplyStyling();
 }
 
@@ -205,7 +206,6 @@
   use_deemphasized_font_ = deemphasize;
   cached_classifications_.reset();
   wrap_text_lines_ = line.num_text_lines() > 1;
-  render_text_.reset();
   render_text_ = CreateRenderText(base::string16());
 
   for (const SuggestionAnswer::TextField& text_field : line.text_fields())
@@ -222,10 +222,11 @@
   }
 
   // Add the "additional" and "status" text from |line|, if any.
-  // Also updates preferred size.
   AppendExtraText(line);
 
   UpdateLineHeight();
+  SetPreferredSize(CalculatePreferredSize());
+  SchedulePaint();
 }
 
 void OmniboxTextView::AppendExtraText(const SuggestionAnswer::ImageLine& line) {
@@ -275,6 +276,7 @@
 
   UpdateLineHeight();
   SetPreferredSize(CalculatePreferredSize());
+  SchedulePaint();
 }
 
 std::unique_ptr<gfx::RenderText> OmniboxTextView::CreateRenderText(
diff --git a/chrome/browser/ui/views/status_bubble_views.cc b/chrome/browser/ui/views/status_bubble_views.cc
index 86c6093..a9d9403 100644
--- a/chrome/browser/ui/views/status_bubble_views.cc
+++ b/chrome/browser/ui/views/status_bubble_views.cc
@@ -700,6 +700,11 @@
     popup_->SetVisibilityChangedAnimationsEnabled(false);
     popup_->SetOpacity(0.f);
     popup_->SetContentsView(view_);
+#if !defined(OS_MACOSX)
+    // Stack the popup above the base widget and below higher z-order windows.
+    // This is unnecessary and even detrimental on Mac, see CreateBubbleWidget.
+    popup_->StackAboveWidget(frame);
+#endif
     RepositionPopup();
   }
 }
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index 6c43c63..a791efd 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -77,8 +77,8 @@
       AddChildView(std::make_unique<views::InkDropContainerView>());
 
   SetInkDropMode(InkDropMode::ON);
-  set_ink_drop_visible_opacity(0.08f);
-  set_ink_drop_highlight_opacity(0.1f);
+  set_ink_drop_highlight_opacity(0.16f);
+  set_ink_drop_visible_opacity(0.14f);
 
   SetInstallFocusRingOnFocus(true);
 }
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index c04d3b7d..095ad732 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -713,7 +713,7 @@
   // color.
   const ui::ThemeProvider* theme_provider = GetThemeProvider();
   if (!theme_provider)
-    return button_color_;
+    return foreground_color_;
 
   switch (state) {
     case TabAlertState::AUDIO_PLAYING:
@@ -733,10 +733,10 @@
     case TabAlertState::SERIAL_CONNECTED:
     case TabAlertState::NONE:
     case TabAlertState::VR_PRESENTING_IN_HEADSET:
-      return button_color_;
+      return foreground_color_;
     default:
       NOTREACHED();
-      return button_color_;
+      return foreground_color_;
   }
 }
 
@@ -1019,16 +1019,13 @@
 void Tab::UpdateForegroundColors() {
   TabStyle::TabColors colors = tab_style_->CalculateColors();
 
-  icon_->SetBackgroundColor(colors.background_color);
-  title_->SetEnabledColor(colors.title_color);
+  title_->SetEnabledColor(colors.foreground_color);
 
-  close_button_->SetIconColors(
-      colors.button_icon_idle_color, colors.button_icon_hovered_color,
-      colors.button_icon_hovered_color, colors.button_background_hovered_color,
-      colors.button_background_pressed_color);
+  close_button_->SetIconColors(colors.foreground_color,
+                               colors.background_color);
 
-  if (button_color_ != colors.button_icon_idle_color) {
-    button_color_ = colors.button_icon_idle_color;
+  if (foreground_color_ != colors.foreground_color) {
+    foreground_color_ = colors.foreground_color;
     alert_indicator_->OnParentTabButtonColorChanged();
   }
 
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index a7c9074f..e3ffbb2 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -295,8 +295,8 @@
   // padding between them to space them out visually.
   bool extra_alert_indicator_padding_ = false;
 
-  // The current color of the alert indicator and close button icons.
-  SkColor button_color_ = SK_ColorTRANSPARENT;
+  // The tab foreground color (title, buttons).
+  SkColor foreground_color_ = SK_ColorTRANSPARENT;
 
   // Indicates whether the mouse is currently hovered over the tab. This is
   // different from View::IsMouseHovered() which does a naive intersection with
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc
index 0931e67..f110c79 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -22,7 +22,9 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/rect_based_targeting_utils.h"
+#include "ui/views/view_class_properties.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
@@ -40,9 +42,15 @@
   SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
   SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
   SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
-  // Disable animation so that the red danger sign shows up immediately
-  // to help avoid mis-clicks.
+
+  SetInkDropMode(InkDropMode::ON);
+  set_ink_drop_highlight_opacity(0.16f);
+  set_ink_drop_visible_opacity(0.14f);
+
+  // Disable animation so that the hover indicator shows up immediately to help
+  // avoid mis-clicks.
   SetAnimationDuration(0);
+  GetInkDrop()->SetHoverHighlightFadeDurationMs(0);
 
   SetInstallFocusRingOnFocus(true);
 }
@@ -55,16 +63,11 @@
                                                   : kGlyphWidth;
 }
 
-void TabCloseButton::SetIconColors(SkColor icon_color,
-                                   SkColor hovered_icon_color,
-                                   SkColor pressed_icon_color,
-                                   SkColor hovered_color,
-                                   SkColor pressed_color) {
-  icon_colors_[views::Button::STATE_NORMAL] = icon_color;
-  icon_colors_[views::Button::STATE_HOVERED] = hovered_icon_color;
-  icon_colors_[views::Button::STATE_PRESSED] = pressed_icon_color;
-  highlight_colors_[views::Button::STATE_HOVERED] = hovered_color;
-  highlight_colors_[views::Button::STATE_PRESSED] = pressed_color;
+void TabCloseButton::SetIconColors(SkColor foreground_color,
+                                   SkColor background_color) {
+  icon_color_ = foreground_color;
+  set_ink_drop_base_color(
+      color_utils::GetColorWithMaxContrast(background_color));
 }
 
 views::View* TabCloseButton::GetTooltipHandlerForPoint(
@@ -109,11 +112,10 @@
 
 void TabCloseButton::Layout() {
   ImageButton::Layout();
-  if (focus_ring()) {
-    SkPath path;
-    path.addOval(gfx::RectToSkRect(GetMirroredRect(GetContentsBounds())));
-    focus_ring()->SetPath(path);
-  }
+  auto path = std::make_unique<SkPath>();
+  gfx::Point center = GetMirroredRect(GetContentsBounds()).CenterPoint();
+  path->addCircle(center.x(), center.y(), GetWidth() / 2);
+  SetProperty(views::kHighlightPathKey, path.release());
 }
 
 gfx::Size TabCloseButton::CalculatePreferredSize() const {
@@ -125,11 +127,18 @@
 }
 
 void TabCloseButton::PaintButtonContents(gfx::Canvas* canvas) {
-  ButtonState button_state = state();
-  // Draw the background circle highlight.
-  if (button_state != views::Button::STATE_NORMAL)
-    DrawHighlight(canvas, button_state);
-  DrawCloseGlyph(canvas, button_state);
+  cc::PaintFlags flags;
+  constexpr float kStrokeWidth = 1.5f;
+  float touch_scale = float{GetWidth()} / kGlyphWidth;
+  float size = (kGlyphWidth - 8) * touch_scale - kStrokeWidth;
+  gfx::RectF glyph_bounds(GetContentsBounds());
+  glyph_bounds.ClampToCenteredSize(gfx::SizeF(size, size));
+  flags.setAntiAlias(true);
+  flags.setStrokeWidth(kStrokeWidth);
+  flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
+  flags.setColor(icon_color_);
+  canvas->DrawLine(glyph_bounds.origin(), glyph_bounds.bottom_right(), flags);
+  canvas->DrawLine(glyph_bounds.bottom_left(), glyph_bounds.top_right(), flags);
 }
 
 views::View* TabCloseButton::TargetForRect(views::View* root,
@@ -164,29 +173,3 @@
   mask->addRect(gfx::RectToSkRect(GetMirroredRect(GetContentsBounds())));
   return true;
 }
-
-void TabCloseButton::DrawHighlight(gfx::Canvas* canvas, ButtonState state) {
-  SkPath path;
-  gfx::Point center = GetContentsBounds().CenterPoint();
-  path.setFillType(SkPath::kEvenOdd_FillType);
-  path.addCircle(center.x(), center.y(), GetWidth() / 2);
-  cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setColor(highlight_colors_[state]);
-  canvas->DrawPath(path, flags);
-}
-
-void TabCloseButton::DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state) {
-  cc::PaintFlags flags;
-  constexpr float kStrokeWidth = 1.5f;
-  float touch_scale = float{GetWidth()} / kGlyphWidth;
-  float size = (kGlyphWidth - 8) * touch_scale - kStrokeWidth;
-  gfx::RectF glyph_bounds(GetContentsBounds());
-  glyph_bounds.ClampToCenteredSize(gfx::SizeF(size, size));
-  flags.setAntiAlias(true);
-  flags.setStrokeWidth(kStrokeWidth);
-  flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
-  flags.setColor(icon_colors_[state]);
-  canvas->DrawLine(glyph_bounds.origin(), glyph_bounds.bottom_right(), flags);
-  canvas->DrawLine(glyph_bounds.bottom_left(), glyph_bounds.top_right(), flags);
-}
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.h b/chrome/browser/ui/views/tabs/tab_close_button.h
index fd7fbee..d03918a 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.h
+++ b/chrome/browser/ui/views/tabs/tab_close_button.h
@@ -35,13 +35,9 @@
   // colors to use. It must also be called when the background color of the tab
   // changes (this class does not track tab activation state), and when the
   // theme changes.
-  void SetIconColors(SkColor icon_color,
-                     SkColor hovered_icon_color,
-                     SkColor pressed_icon_color,
-                     SkColor hovered_color,
-                     SkColor pressed_color);
+  void SetIconColors(SkColor foreground_color, SkColor background_color);
 
-  // views::View:
+  // views::ImageButton:
   View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseMoved(const ui::MouseEvent& event) override;
@@ -59,16 +55,9 @@
   views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
   bool GetHitTestMask(SkPath* mask) const override;
 
-  // Draw the highlight circle.
-  void DrawHighlight(gfx::Canvas* canvas, ButtonState state);
-
-  // Draw the close "X" glyph.
-  void DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state);
-
   MouseEventCallback mouse_event_callback_;
 
-  SkColor icon_colors_[views::Button::STATE_PRESSED + 1];
-  SkColor highlight_colors_[views::Button::STATE_PRESSED + 1];
+  SkColor icon_color_ = gfx::kPlaceholderColor;
 
   DISALLOW_COPY_AND_ASSIGN(TabCloseButton);
 };
diff --git a/chrome/browser/ui/views/tabs/tab_icon.cc b/chrome/browser/ui/views/tabs/tab_icon.cc
index a3f139f..9d1641b5 100644
--- a/chrome/browser/ui/views/tabs/tab_icon.cc
+++ b/chrome/browser/ui/views/tabs/tab_icon.cc
@@ -165,11 +165,6 @@
     SchedulePaint();
 }
 
-void TabIcon::SetBackgroundColor(SkColor bg_color) {
-  bg_color_ = bg_color;
-  SchedulePaint();
-}
-
 void TabIcon::OnPaint(gfx::Canvas* canvas) {
   // This is used to log to UMA. NO EARLY RETURNS!
   base::ElapsedTimer paint_timer;
diff --git a/chrome/browser/ui/views/tabs/tab_icon.h b/chrome/browser/ui/views/tabs/tab_icon.h
index 1053849b..33d5209 100644
--- a/chrome/browser/ui/views/tabs/tab_icon.h
+++ b/chrome/browser/ui/views/tabs/tab_icon.h
@@ -64,8 +64,6 @@
   // strip in order to keep the throbbers in sync.
   void StepLoadingAnimation(const base::TimeDelta& elapsed_time);
 
-  void SetBackgroundColor(SkColor color);
-
  private:
   class CrashAnimation;
   friend CrashAnimation;
@@ -161,8 +159,6 @@
 
   bool can_paint_to_layer_ = false;
 
-  SkColor bg_color_ = SK_ColorBLACK;
-
   bool has_tab_renderer_data_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TabIcon);
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index 1899c26..f0337831 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -370,17 +370,6 @@
 }
 
 TabStyle::TabColors GM2TabStyle::CalculateColors() const {
-  const ui::ThemeProvider* theme_provider = tab_->GetThemeProvider();
-
-  // These ratios are calculated from the default Chrome theme colors.
-  // Active/inactive are the contrast ratios of the close X against the tab
-  // background. Hovered/pressed are the contrast ratios of the highlight circle
-  // against the tab background.
-  constexpr float kMinimumActiveContrastRatio = 6.05f;
-  constexpr float kMinimumInactiveContrastRatio = 4.61f;
-  constexpr float kMinimumHoveredContrastRatio = 5.02f;
-  constexpr float kMinimumPressedContrastRatio = 4.41f;
-
   // In some cases, inactive tabs may have background more like active tabs than
   // inactive tabs, so colors should be adapted to ensure appropriate contrast.
   // In particular, text should have plenty of contrast in all cases, so switch
@@ -394,48 +383,14 @@
   } else if (tab_->mouse_hovered()) {
     expected_opacity = GetHoverOpacity();
   }
-  const SkColor bg_color = color_utils::AlphaBlend(
+  const SkColor background_color = color_utils::AlphaBlend(
       GetTabBackgroundColor(TAB_ACTIVE), GetTabBackgroundColor(TAB_INACTIVE),
       expected_opacity);
 
-  SkColor title_color = tab_->controller()->GetTabForegroundColor(
-      expected_opacity > 0.5f ? TAB_ACTIVE : TAB_INACTIVE, bg_color);
+  const SkColor foreground_color = tab_->controller()->GetTabForegroundColor(
+      expected_opacity > 0.5f ? TAB_ACTIVE : TAB_INACTIVE, background_color);
 
-  const SkColor base_hovered_color = theme_provider->GetColor(
-      ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_HOVER);
-  const SkColor base_pressed_color = theme_provider->GetColor(
-      ThemeProperties::COLOR_TAB_CLOSE_BUTTON_BACKGROUND_PRESSED);
-
-  const auto get_color_for_contrast_ratio =
-      [](SkColor fg_color, SkColor bg_color, float contrast_ratio) {
-        return color_utils::BlendForMinContrast(bg_color, bg_color, fg_color,
-                                                contrast_ratio)
-            .color;
-      };
-
-  const SkColor generated_icon_color = get_color_for_contrast_ratio(
-      title_color, bg_color,
-      tab_->IsActive() ? kMinimumActiveContrastRatio
-                       : kMinimumInactiveContrastRatio);
-  const SkColor generated_hovered_color = get_color_for_contrast_ratio(
-      base_hovered_color, bg_color, kMinimumHoveredContrastRatio);
-  const SkColor generated_pressed_color = get_color_for_contrast_ratio(
-      base_pressed_color, bg_color, kMinimumPressedContrastRatio);
-
-  const SkColor generated_hovered_icon_color =
-      color_utils::BlendForMinContrast(title_color, generated_hovered_color)
-          .color;
-  const SkColor generated_pressed_icon_color =
-      color_utils::BlendForMinContrast(title_color, generated_pressed_color)
-          .color;
-
-  return {bg_color,
-          title_color,
-          generated_icon_color,
-          generated_hovered_icon_color,
-          generated_pressed_icon_color,
-          generated_hovered_color,
-          generated_pressed_color};
+  return {foreground_color, background_color};
 }
 
 void GM2TabStyle::PaintTab(gfx::Canvas* canvas, const SkPath& clip) const {
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 bddbe14..52efe92 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
@@ -68,8 +68,8 @@
       // a right-click but long-pressing yields the same result. All menus
       // here use a touchable layout.
       views::MenuConfig::instance().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;
+      // 3 menu items we don't want, and go over part of the one we want.
+      3.2 * views::MenuConfig::instance().touchable_menu_height;
   generator.MoveMouseBy(0, -offset);
   generator.ReleaseRightButton();
 }
diff --git a/chrome/browser/vr/text_perftest.cc b/chrome/browser/vr/text_perftest.cc
index e24071e..6bb1d26 100644
--- a/chrome/browser/vr/text_perftest.cc
+++ b/chrome/browser/vr/text_perftest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/vr/test/constants.h"
 #include "chrome/browser/vr/test/gl_test_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_result_reporter.h"
 #include "testing/perf/perf_test.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
@@ -35,17 +36,26 @@
   }
 
   void TearDown() override {
+    PrintResults();
     text_element_.reset();
     provider_.reset();
     gl_test_environment_.reset();
   }
 
  protected:
-  void PrintResults(const std::string& name) {
-    perf_test::PrintResult("TextPerfTest", ".render_time_avg", name,
-                           timer_.TimePerLap().InMillisecondsF(), "ms", true);
-    perf_test::PrintResult("TextPerfTest", ".number_of_runs", name,
-                           static_cast<size_t>(timer_.NumLaps()), "runs", true);
+  void SetupReporter(const std::string& test_name,
+                     const std::string& story_name) {
+    reporter_ =
+        std::make_unique<perf_test::PerfResultReporter>(test_name, story_name);
+    reporter_->RegisterImportantMetric(".render_time_avg", "ms");
+    reporter_->RegisterImportantMetric(".number_of_runs", "runs");
+  }
+
+  void PrintResults() {
+    reporter_->AddResult(".render_time_avg",
+                         timer_.TimePerLap().InMillisecondsF());
+    reporter_->AddResult(".number_of_runs",
+                         static_cast<size_t>(timer_.NumLaps()));
   }
 
   void RenderAndLapTimer() {
@@ -57,6 +67,9 @@
   }
 
   std::unique_ptr<Text> text_element_;
+  // It would be better to initialize this during SetUp(), but there doesn't
+  // appear to be a good way to get the test name from within testing::Test.
+  std::unique_ptr<perf_test::PerfResultReporter> reporter_;
   base::LapTimer timer_;
 
  private:
@@ -65,6 +78,7 @@
 };
 
 TEST_F(TextPerfTest, RenderLoremIpsum100Chars) {
+  SetupReporter("TextPerfTest", "render_lorem_ipsum_100_chars");
   base::string16 text = base::UTF8ToUTF16(kLoremIpsum100Chars);
   timer_.Reset();
   for (size_t i = 0; i < kNumberOfRuns; i++) {
@@ -72,10 +86,10 @@
     text_element_->SetText(text);
     RenderAndLapTimer();
   }
-  PrintResults("render_lorem_ipsum_100_chars");
 }
 
 TEST_F(TextPerfTest, RenderLoremIpsum700Chars) {
+  SetupReporter("TextPerfTest", "render_lorem_ipsum_700_chars");
   base::string16 text = base::UTF8ToUTF16(kLoremIpsum700Chars);
   timer_.Reset();
   for (size_t i = 0; i < kNumberOfRuns; i++) {
@@ -83,7 +97,6 @@
     text_element_->SetText(text);
     RenderAndLapTimer();
   }
-  PrintResults("render_lorem_ipsum_700_chars");
 }
 
 }  // namespace vr
diff --git a/chrome/common/search/BUILD.gn b/chrome/common/search/BUILD.gn
index 3175d5b..70b75df2 100644
--- a/chrome/common/search/BUILD.gn
+++ b/chrome/common/search/BUILD.gn
@@ -12,6 +12,7 @@
   ]
   deps = [
     "//base",
+    "//chrome:strings",
     "//chrome/common/themes:autogenerated_theme_util",
     "//skia",
   ]
diff --git a/chrome/common/search/generate_colors_info.cc b/chrome/common/search/generate_colors_info.cc
index 1d77371..bba9e5b 100644
--- a/chrome/common/search/generate_colors_info.cc
+++ b/chrome/common/search/generate_colors_info.cc
@@ -16,10 +16,10 @@
 // $2 - red value of primary color
 // $3 - green value of primary color
 // $4 - blue value of primary color
-// $5 - color label
+// $5 - color label id
 // $6 - icon data
 const char kColorInfoLineTemplate[] =
-    "   ColorInfo($1, SkColorSetRGB($2, $3, $4), \"$5\", "
+    "   ColorInfo($1, SkColorSetRGB($2, $3, $4), $5, "
     "\"data:image/svg+xml;base64,$6\")";
 
 // Template for the generated file content.
@@ -81,7 +81,7 @@
   subst.push_back(base::NumberToString(SkColorGetR(color_info.color)));
   subst.push_back(base::NumberToString(SkColorGetG(color_info.color)));
   subst.push_back(base::NumberToString(SkColorGetB(color_info.color)));
-  subst.push_back(color_info.label);
+  subst.push_back(base::NumberToString(color_info.label_id));
   subst.push_back(GenerateIconDataForColor(color_info.color));
   return base::ReplaceStringPlaceholders(kColorInfoLineTemplate, subst, NULL);
 }
diff --git a/chrome/common/search/selected_colors_info.h b/chrome/common/search/selected_colors_info.h
index 9190d8e1..d1c6aa45 100644
--- a/chrome/common/search/selected_colors_info.h
+++ b/chrome/common/search/selected_colors_info.h
@@ -7,51 +7,57 @@
 
 #include <stdint.h>
 
+#include "chrome/grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace chrome_colors {
 
 struct ColorInfo {
-  constexpr ColorInfo(int id, SkColor color, const char* label)
-      : ColorInfo(id, color, label, nullptr) {}
+  constexpr ColorInfo(int id, SkColor color, int label_id)
+      : ColorInfo(id, color, label_id, nullptr) {}
   constexpr ColorInfo(int id,
                       SkColor color,
-                      const char* label,
+                      int label_id,
                       const char* icon_data)
-      : id(id), color(color), label(label), icon_data(icon_data) {}
+      : id(id), color(color), label_id(label_id), icon_data(icon_data) {}
   int id;
   SkColor color;
-  const char* label;
+  int label_id;
   const char* icon_data;
 };
 
-// TODO(gayane): Add colors selected by UX.
 // List of preselected colors to show in Chrome Colors menu. This array should
 // always be in sync with ChromeColorsInfo in enums.xml.
 constexpr ColorInfo kSelectedColorsInfo[] = {
     // 0  - reserved for any color not in this set.
-    ColorInfo(1, SkColorSetRGB(239, 235, 233), "Elephant"),
-    ColorInfo(2, SkColorSetRGB(120, 127, 145), "Light grey"),
-    ColorInfo(3, SkColorSetRGB(55, 71, 79), "Midnight"),
-    ColorInfo(4, SkColorSetRGB(0, 0, 0), "Black"),
-    ColorInfo(5, SkColorSetRGB(252, 219, 201), "Beige/White"),
-    ColorInfo(6, SkColorSetRGB(255, 249, 228), "Yellow/White"),
-    ColorInfo(7, SkColorSetRGB(203, 233, 191), "Green/White"),
-    ColorInfo(8, SkColorSetRGB(221, 244, 249), "Light Teal/White"),
-    ColorInfo(9, SkColorSetRGB(233, 212, 255), "Light Purple/White"),
-    ColorInfo(10, SkColorSetRGB(249, 226, 237), "Pink/White"),
-    ColorInfo(11, SkColorSetRGB(227, 171, 154), "Beige"),
-    ColorInfo(12, SkColorSetRGB(255, 171, 64), "Orange"),
-    ColorInfo(13, SkColorSetRGB(67, 160, 71), "Light Green"),
-    ColorInfo(14, SkColorSetRGB(25, 157, 169), "Light Teal"),
-    ColorInfo(15, SkColorSetRGB(93, 147, 228), "Light Blue"),
-    ColorInfo(16, SkColorSetRGB(255, 174, 189), "Pink"),
-    ColorInfo(17, SkColorSetRGB(189, 22, 92), "Dark Pink/Red"),
-    ColorInfo(18, SkColorSetRGB(183, 28, 28), "Dark Red/Orange"),
-    ColorInfo(19, SkColorSetRGB(46, 125, 50), "Dark Green"),
-    ColorInfo(20, SkColorSetRGB(0, 110, 120), "Dark Teal"),
-    ColorInfo(21, SkColorSetRGB(21, 101, 192), "Dark Blue"),
-    ColorInfo(22, SkColorSetRGB(91, 54, 137), "Dark Purple"),
+    ColorInfo(1, SkColorSetRGB(239, 235, 233), IDS_NTP_COLORS_WARM_GREY),
+    ColorInfo(2, SkColorSetRGB(120, 127, 145), IDS_NTP_COLORS_COOL_GREY),
+    ColorInfo(3, SkColorSetRGB(55, 71, 79), IDS_NTP_COLORS_MIDNIGHT_BLUE),
+    ColorInfo(4, SkColorSetRGB(0, 0, 0), IDS_NTP_COLORS_BLACK),
+    ColorInfo(5, SkColorSetRGB(252, 219, 201), IDS_NTP_COLORS_BEIGE_AND_WHITE),
+    ColorInfo(6, SkColorSetRGB(255, 249, 228), IDS_NTP_COLORS_YELLOW_AND_WHITE),
+    ColorInfo(7, SkColorSetRGB(203, 233, 191), IDS_NTP_COLORS_GREEN_AND_WHITE),
+    ColorInfo(8,
+              SkColorSetRGB(221, 244, 249),
+              IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE),
+    ColorInfo(9,
+              SkColorSetRGB(233, 212, 255),
+              IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE),
+    ColorInfo(10, SkColorSetRGB(249, 226, 237), IDS_NTP_COLORS_PINK_AND_WHITE),
+    ColorInfo(11, SkColorSetRGB(227, 171, 154), IDS_NTP_COLORS_BEIGE),
+    ColorInfo(12, SkColorSetRGB(255, 171, 64), IDS_NTP_COLORS_ORANGE),
+    ColorInfo(13, SkColorSetRGB(67, 160, 71), IDS_NTP_COLORS_LIGHT_GREEN),
+    ColorInfo(14, SkColorSetRGB(25, 157, 169), IDS_NTP_COLORS_LIGHT_TEAL),
+    ColorInfo(15, SkColorSetRGB(93, 147, 228), IDS_NTP_COLORS_LIGHT_BLUE),
+    ColorInfo(16, SkColorSetRGB(255, 174, 189), IDS_NTP_COLORS_PINK),
+    ColorInfo(17, SkColorSetRGB(189, 22, 92), IDS_NTP_COLORS_DARK_PINK_AND_RED),
+    ColorInfo(18,
+              SkColorSetRGB(183, 28, 28),
+              IDS_NTP_COLORS_DARK_RED_AND_ORANGE),
+    ColorInfo(19, SkColorSetRGB(46, 125, 50), IDS_NTP_COLORS_DARK_GREEN),
+    ColorInfo(20, SkColorSetRGB(0, 110, 120), IDS_NTP_COLORS_DARK_TEAL),
+    ColorInfo(21, SkColorSetRGB(21, 101, 192), IDS_NTP_COLORS_DARK_BLUE),
+    ColorInfo(22, SkColorSetRGB(91, 54, 137), IDS_NTP_COLORS_DARK_PURPLE),
 };
 
 }  // namespace chrome_colors
diff --git a/chrome/installer/mac/signing/modification.py b/chrome/installer/mac/signing/modification.py
index 62ae769..e734f8e 100644
--- a/chrome/installer/mac/signing/modification.py
+++ b/chrome/installer/mac/signing/modification.py
@@ -69,17 +69,12 @@
 
         # See build/mac/tweak_info_plist.py and
         # chrome/browser/mac/keystone_glue.mm.
-        keys_to_remove = set()
         for key in app_plist.keys():
             if not key.startswith(_KS_CHANNEL_ID + '-'):
                 continue
-            if dist.channel:
-                orig_channel, tag = key.split('-')
-                app_plist[key] = '{}-{}'.format(dist.channel, tag)
-            else:
-                keys_to_remove.add(key)
-        for key in keys_to_remove:
-            del app_plist[key]
+            orig_channel, tag = key.split('-')
+            channel_str = dist.channel if dist.channel else ''
+            app_plist[key] = '{}-{}'.format(channel_str, tag)
 
 
 def _replace_icons(paths, dist, config):
diff --git a/chrome/installer/mac/signing/modification_test.py b/chrome/installer/mac/signing/modification_test.py
index e612ac7..5f30778 100644
--- a/chrome/installer/mac/signing/modification_test.py
+++ b/chrome/installer/mac/signing/modification_test.py
@@ -15,8 +15,7 @@
         '$W/App Product.app/Contents/Info.plist': {
             'CFBundleIdentifier': bundle_id,
             'KSProductID': 'test.ksproduct',
-            'KSChannelID': 'stable',
-            'KSChannelID-full': 'stable',
+            'KSChannelID-full': '-full',
         },
         '$W/App Product Canary.app/Contents/Frameworks/Product Framework.framework/XPCServices/AlertNotificationService.xpc/Contents/Info.plist':
             {
@@ -90,7 +89,8 @@
         plistlib.writePlist.assert_called_with(
             {
                 'CFBundleIdentifier': config.base_bundle_id,
-                'KSProductID': 'test.ksproduct'
+                'KSProductID': 'test.ksproduct',
+                'KSChannelID-full': '-full'
             },
             '$W/App Product.app/Contents/Info.plist',
         )
@@ -122,7 +122,8 @@
             {
                 'CFBundleIdentifier': config.base_bundle_id,
                 'KSProductID': 'test.ksproduct',
-                'KSBrandID': 'MOO'
+                'KSBrandID': 'MOO',
+                'KSChannelID-full': '-full'
             },
             '$W/App Product.app/Contents/Info.plist',
         )
@@ -186,6 +187,7 @@
             {
                 'CFBundleIdentifier': config.base_bundle_id,
                 'KSProductID': 'test.ksproduct',
+                'KSChannelID-full': '-full',
                 'CrProductDirName': 'Farmland/Cows'
             },
             '$W/App Product.app/Contents/Info.plist',
@@ -218,6 +220,7 @@
             {
                 'CFBundleIdentifier': config.base_bundle_id,
                 'KSProductID': 'test.ksproduct',
+                'KSChannelID-full': '-full',
                 'CFBundleSignature': 'Mooo'
             },
             '$W/App Product.app/Contents/Info.plist',
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 6ffbcce..e25449b 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -46,6 +46,7 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_script_source.h"
 #include "third_party/blink/public/web/web_view.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -1302,7 +1303,7 @@
         gin::DataObjectBuilder(isolate)
             .Set("id", color_info.id)
             .Set("color", SkColorToArray(isolate, color_info.color))
-            .Set("label", std::string(color_info.label))
+            .Set("label", l10n_util::GetStringUTF16(color_info.label_id))
             .Set("icon", std::string(color_info.icon_data))
             .Build();
     v8_colors->CreateDataProperty(context, i++, v8_color_info).Check();
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index e4aa438..c96476c 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -125,7 +125,8 @@
   std::unique_ptr<chromeos::device_sync::DeviceSyncBase> BuildInstance(
       signin::IdentityManager* identity_manager,
       gcm::GCMDriver* gcm_driver,
-      service_manager::Connector* connector,
+      mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+          pref_store_connector,
       const chromeos::device_sync::GcmDeviceInfoProvider*
           gcm_device_info_provider,
       chromeos::device_sync::ClientAppMetadataProvider*
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request_blocking/service_worker_background.js b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request_blocking/service_worker_background.js
index 7159b05..6a17567 100644
--- a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request_blocking/service_worker_background.js
+++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request_blocking/service_worker_background.js
@@ -4,7 +4,6 @@
 
 // Register a listener with a callback that blocks all requests.
 chrome.webRequest.onBeforeRequest.addListener(function localListener(details) {
-  chrome.webRequest.onBeforeRequest.removeListener(localListener);
   return {cancel: true};
 }, { urls: ['<all_urls>']}, ['blocking']);
 
diff --git a/chrome/test/data/extensions/theme/Cached Theme.pak b/chrome/test/data/extensions/theme/Cached Theme.pak
index c55c07c..405498f8c 100644
--- a/chrome/test/data/extensions/theme/Cached Theme.pak
+++ b/chrome/test/data/extensions/theme/Cached Theme.pak
Binary files differ
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js
index d972a91c..1326a35d3 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js
@@ -68,7 +68,7 @@
     });
 
     test('showing menu in toolbar is dependent on narrow mode', () => {
-      const toolbar = assert(ui.$$('cr-toolbar'));
+      const toolbar = assert(ui.$$('os-toolbar'));
       toolbar.narrow = true;
       assertTrue(toolbar.showMenu);
 
@@ -98,7 +98,7 @@
 
     test('app drawer closes when exiting narrow mode', async () => {
       const drawer = ui.$.drawer;
-      const toolbar = ui.$$('cr-toolbar');
+      const toolbar = ui.$$('os-toolbar');
 
       // Mimic narrow mode and open the drawer.
       toolbar.narrow = true;
@@ -167,7 +167,7 @@
     });
 
     test('URL initiated search propagates to search box', () => {
-      toolbar = /** @type {!CrToolbarElement} */ (ui.$$('cr-toolbar'));
+      toolbar = /** @type {!OsToolbarElement} */ (ui.$$('os-toolbar'));
       const searchField =
           /** @type {CrToolbarSearchFieldElement} */ (toolbar.getSearchField());
       assertEquals('', searchField.getSearchInput().value);
@@ -179,7 +179,7 @@
     });
 
     test('search box initiated search propagates to URL', () => {
-      toolbar = /** @type {!CrToolbarElement} */ (ui.$$('cr-toolbar'));
+      toolbar = /** @type {!OsToolbarElement} */ (ui.$$('os-toolbar'));
       const searchField =
           /** @type {CrToolbarSearchFieldElement} */ (toolbar.getSearchField());
 
@@ -200,7 +200,7 @@
     });
 
     test('whitespace only search query is ignored', () => {
-      toolbar = /** @type {!CrToolbarElement} */ (ui.$$('cr-toolbar'));
+      toolbar = /** @type {!OsToolbarElement} */ (ui.$$('os-toolbar'));
       const searchField =
           /** @type {CrToolbarSearchFieldElement} */ (toolbar.getSearchField());
       searchField.setValue('    ');
diff --git a/chrome/updater/BRANDING b/chrome/updater/BRANDING
new file mode 100644
index 0000000..49eb4d5
--- /dev/null
+++ b/chrome/updater/BRANDING
@@ -0,0 +1,4 @@
+COMPANY_FULLNAME=Google LLC
+COMPANY_SHORTNAME=Google
+PRODUCT_FULLNAME=GoogleUpdater
+COPYRIGHT=Copyright 2019 The Chromium Authors. All rights reserved.
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index e161ec5..6de5b53 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -65,6 +65,7 @@
   process_version("version_header") {
     sources = [
       "//chrome/VERSION",
+      "BRANDING",
     ]
     template_file = "updater_version.h.in"
     output = "$target_gen_dir/updater_version.h"
diff --git a/chrome/updater/crash_reporter.cc b/chrome/updater/crash_reporter.cc
index 5607fb7..41d7138b 100644
--- a/chrome/updater/crash_reporter.cc
+++ b/chrome/updater/crash_reporter.cc
@@ -93,7 +93,7 @@
 
   // Disable rate-limiting until this is fixed:
   //   https://bugs.chromium.org/p/crashpad/issues/detail?id=23
-  command_line->AppendSwitch(kNoRateLimit);
+  command_line->AppendSwitch(kNoRateLimitSwitch);
 
   std::vector<base::CommandLine::StringType> argv = command_line->argv();
 
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index 4deeeed..27012e5 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -145,43 +145,13 @@
 
 int UpdaterUninstall() {
 #if defined(OS_WIN)
-  return updater::Uninstall();
+  return Uninstall();
 #else
   return -1;
 #endif
 }
 
-}  // namespace
-
-int UpdaterMain(int argc, const char* const* argv) {
-  base::PlatformThread::SetName("UpdaterMain");
-  base::AtExitManager exit_manager;
-
-  base::CommandLine::Init(argc, argv);
-  const auto* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(kTestSwitch))
-    return 0;
-
-  InitLogging(*command_line);
-
-  if (command_line->HasSwitch(kCrashHandlerSwitch))
-    return CrashReporterMain();
-
-  InitializeUpdaterMain();
-
-  if (command_line->HasSwitch(kCrashMeSwitch)) {
-    int* ptr = nullptr;
-    return *ptr;
-  }
-
-  if (command_line->HasSwitch(kInstall)) {
-    return UpdaterInstall();
-  }
-
-  if (command_line->HasSwitch(kUninstall)) {
-    return UpdaterUninstall();
-  }
-
+int UpdaterUpdateApps() {
   auto installer = base::MakeRefCounted<Installer>(
       std::vector<uint8_t>(std::cbegin(mimo_hash), std::cend(mimo_hash)));
   installer->FindInstallOfApp();
@@ -248,8 +218,53 @@
     runloop.Run();
   }
 
-  TerminateUpdaterMain();
   return 0;
 }
 
+}  // namespace
+
+int HandleUpdaterCommands(const base::CommandLine* command_line) {
+  DCHECK(!command_line->HasSwitch(kCrashHandlerSwitch));
+
+  if (command_line->HasSwitch(kCrashMeSwitch)) {
+    int* ptr = nullptr;
+    return *ptr;
+  }
+
+  if (command_line->HasSwitch(kInstallSwitch)) {
+    return UpdaterInstall();
+  }
+
+  if (command_line->HasSwitch(kUninstallSwitch)) {
+    return UpdaterUninstall();
+  }
+
+  if (command_line->HasSwitch(kUpdateAppsSwitch)) {
+    return UpdaterUpdateApps();
+  }
+
+  VLOG(1) << "Unknown command line switch.";
+  return -1;
+}
+
+int UpdaterMain(int argc, const char* const* argv) {
+  base::PlatformThread::SetName("UpdaterMain");
+  base::AtExitManager exit_manager;
+
+  base::CommandLine::Init(argc, argv);
+  const auto* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(kTestSwitch))
+    return 0;
+
+  InitLogging(*command_line);
+
+  if (command_line->HasSwitch(kCrashHandlerSwitch))
+    return CrashReporterMain();
+
+  InitializeUpdaterMain();
+  const auto result = HandleUpdaterCommands(command_line);
+  TerminateUpdaterMain();
+  return result;
+}
+
 }  // namespace updater
diff --git a/chrome/updater/updater_constants.cc b/chrome/updater/updater_constants.cc
index 281447b..d726e79 100644
--- a/chrome/updater/updater_constants.cc
+++ b/chrome/updater/updater_constants.cc
@@ -8,12 +8,15 @@
 
 const char kCrashMeSwitch[] = "crash-me";
 const char kCrashHandlerSwitch[] = "crash-handler";
-const char kInstall[] = "install";
-const char kUninstall[] = "uninstall";
+const char kInstallSwitch[] = "install";
+const char kUninstallSwitch[] = "uninstall";
+const char kUpdateAppsSwitch[] = "ua";
 const char kTestSwitch[] = "test";
 const char kInitDoneNotifierSwitch[] = "init-done-notifier";
-
-const char kNoRateLimit[] = "--no-rate-limit";
+const char kNoRateLimitSwitch[] = "no-rate-limit";
+const char kEnableLoggingSwitch[] = "enable-logging";
+const char kLoggingLevelSwitch[] = "v";
+const char kLoggingModuleSwitch[] = "vmodule";
 
 const char kUpdaterJSONDefaultUrl[] =
     "https://update.googleapis.com/service/update2/json";
diff --git a/chrome/updater/updater_constants.h b/chrome/updater/updater_constants.h
index 37fadddf6..5f473258 100644
--- a/chrome/updater/updater_constants.h
+++ b/chrome/updater/updater_constants.h
@@ -16,22 +16,34 @@
 extern const char kCrashHandlerSwitch[];
 
 // Installs the updater.
-extern const char kInstall[];
+extern const char kInstallSwitch[];
 
 // Uninstalls the updater.
-extern const char kUninstall[];
+extern const char kUninstallSwitch[];
+
+// Updates all apps registered with the updater.
+extern const char kUpdateAppsSwitch[];
 
 // Runs in test mode. Currently, it exits right away.
 extern const char kTestSwitch[];
 
 // Disables throttling for the crash reported until the following bug is fixed:
 // https://bugs.chromium.org/p/crashpad/issues/detail?id=23
-extern const char kNoRateLimit[];
+extern const char kNoRateLimitSwitch[];
 
 // The handle of an event to signal when the initialization of the main process
 // is complete.
 extern const char kInitDoneNotifierSwitch[];
 
+// Enables logging.
+extern const char kEnableLoggingSwitch[];
+
+// Specifies the logging level.
+extern const char kLoggingLevelSwitch[];
+
+// Specifies the logging module filter.
+extern const char kLoggingModuleSwitch[];
+
 // URLs.
 //
 // Omaha server end point.
diff --git a/chrome/updater/updater_version.h.in b/chrome/updater/updater_version.h.in
index 994af06..242c533 100644
--- a/chrome/updater/updater_version.h.in
+++ b/chrome/updater/updater_version.h.in
@@ -8,5 +8,7 @@
 #define UPDATER_VERSION_STRING "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
 
 // Branding Information
-#define PRODUCT_FULLNAME_STRING "ChromeUpdater"
+#define COMPANY_FULLNAME_STRING "@COMPANY_FULLNAME@"
+#define COMPANY_SHORTNAME_STRING "@COMPANY_SHORTNAME@"
+#define PRODUCT_FULLNAME_STRING "@PRODUCT_FULLNAME@"
 #define OFFICIAL_BUILD_STRING "@OFFICIAL_BUILD@"
diff --git a/chrome/updater/util.cc b/chrome/updater/util.cc
index 4f3f696..ced4a55b 100644
--- a/chrome/updater/util.cc
+++ b/chrome/updater/util.cc
@@ -29,7 +29,8 @@
   }
 
   const auto product_data_dir =
-      app_data_dir.AppendASCII(PRODUCT_FULLNAME_STRING);
+      app_data_dir.AppendASCII(COMPANY_SHORTNAME_STRING)
+          .AppendASCII(PRODUCT_FULLNAME_STRING);
   if (!base::CreateDirectory(product_data_dir)) {
     LOG(ERROR) << "Can't create product directory.";
     return false;
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn
index d27a45fc..d3c9fd2 100644
--- a/chrome/updater/win/BUILD.gn
+++ b/chrome/updater/win/BUILD.gn
@@ -28,10 +28,6 @@
     "//build/win:default_exe_manifest",
     "//chrome/updater:common",
   ]
-
-  data_deps = [
-    ":uninstall.cmd",
-  ]
 }
 
 copy("uninstall.cmd") {
@@ -62,6 +58,8 @@
     "net/scoped_hinternet.h",
     "setup/setup.cc",
     "setup/setup.h",
+    "setup/setup_util.cc",
+    "setup/setup_util.h",
     "setup/uninstall.cc",
     "setup/uninstall.h",
     "task_scheduler.cc",
diff --git a/chrome/updater/win/installer/BUILD.gn b/chrome/updater/win/installer/BUILD.gn
index dcb958f9..b7ae096 100644
--- a/chrome/updater/win/installer/BUILD.gn
+++ b/chrome/updater/win/installer/BUILD.gn
@@ -84,6 +84,7 @@
 
     deps = [
       ":updater_runtime_deps",
+      "//chrome/updater/win:uninstall.cmd",
       "//chrome/updater/win:updater",
     ]
 
diff --git a/chrome/updater/win/setup/setup.cc b/chrome/updater/win/setup/setup.cc
index c59b5be8..2848c5c 100644
--- a/chrome/updater/win/setup/setup.cc
+++ b/chrome/updater/win/setup/setup.cc
@@ -7,15 +7,22 @@
 #include <memory>
 #include <vector>
 
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/win/scoped_com_initializer.h"
 #include "chrome/installer/util/copy_tree_work_item.h"
 #include "chrome/installer/util/self_cleaning_temp_dir.h"
 #include "chrome/installer/util/work_item_list.h"
 #include "chrome/updater/updater_constants.h"
 #include "chrome/updater/util.h"
+#include "chrome/updater/win/setup/setup_util.h"
+#include "chrome/updater/win/task_scheduler.h"
 
 namespace updater {
 
@@ -44,6 +51,17 @@
 int Setup() {
   VLOG(1) << __func__;
 
+  auto scoped_com_initializer =
+      std::make_unique<base::win::ScopedCOMInitializer>(
+          base::win::ScopedCOMInitializer::kMTA);
+
+  if (!TaskScheduler::Initialize()) {
+    LOG(ERROR) << "Failed to initialize the scheduler.";
+    return -1;
+  }
+  base::ScopedClosureRunner task_scheduler_terminate_caller(
+      base::BindOnce([]() { TaskScheduler::Terminate(); }));
+
   base::FilePath temp_dir;
   if (!base::GetTempDir(&temp_dir)) {
     LOG(ERROR) << "GetTempDir failed.";
@@ -77,9 +95,18 @@
                                          WorkItem::ALWAYS, base::FilePath()));
   }
 
-  if (!install_list->Do()) {
+  base::CommandLine run_updater_ua_command(product_dir.Append(L"updater.exe"));
+  run_updater_ua_command.AppendSwitch(kUpdateAppsSwitch);
+#if !defined(NDEBUG)
+  run_updater_ua_command.AppendSwitch(kEnableLoggingSwitch);
+  run_updater_ua_command.AppendSwitchASCII(kLoggingLevelSwitch, "1");
+  run_updater_ua_command.AppendSwitchASCII(kLoggingModuleSwitch,
+                                           "*/chrome/updater/*");
+#endif
+  if (!install_list->Do() || !RegisterUpdateAppsTask(run_updater_ua_command)) {
     LOG(ERROR) << "Install failed, rolling back...";
     install_list->Rollback();
+    UnregisterUpdateAppsTask();
     LOG(ERROR) << "Rollback complete.";
     return -1;
   }
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc
new file mode 100644
index 0000000..fff30e8
--- /dev/null
+++ b/chrome/updater/win/setup/setup_util.cc
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/setup/setup_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "chrome/updater/win/task_scheduler.h"
+
+namespace updater {
+
+namespace {
+
+constexpr base::char16 kTaskName[] = L"GoogleUpdaterUA";
+constexpr base::char16 kTaskDescription[] = L"Update all applications.";
+
+}  // namespace
+
+bool RegisterUpdateAppsTask(const base::CommandLine& run_command) {
+  auto task_scheduler = TaskScheduler::CreateInstance();
+  if (!task_scheduler->RegisterTask(
+          kTaskName, kTaskDescription, run_command,
+          TaskScheduler::TriggerType::TRIGGER_TYPE_HOURLY, true)) {
+    LOG(ERROR) << "RegisterUpdateAppsTask failed.";
+    return false;
+  }
+  VLOG(1) << "RegisterUpdateAppsTask succeeded.";
+  return true;
+}
+
+void UnregisterUpdateAppsTask() {
+  auto task_scheduler = TaskScheduler::CreateInstance();
+  task_scheduler->DeleteTask(kTaskName);
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/setup/setup_util.h b/chrome/updater/win/setup/setup_util.h
new file mode 100644
index 0000000..4a57f32d
--- /dev/null
+++ b/chrome/updater/win/setup/setup_util.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_SETUP_SETUP_UTIL_H_
+#define CHROME_UPDATER_WIN_SETUP_SETUP_UTIL_H_
+
+namespace base {
+class CommandLine;
+}  // namespace base
+
+#include "base/win/windows_types.h"
+
+namespace updater {
+
+bool RegisterUpdateAppsTask(const base::CommandLine& run_command);
+void UnregisterUpdateAppsTask();
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_SETUP_SETUP_UTIL_H_
diff --git a/chrome/updater/win/setup/uninstall.cc b/chrome/updater/win/setup/uninstall.cc
index ca5332c..8767e26 100644
--- a/chrome/updater/win/setup/uninstall.cc
+++ b/chrome/updater/win/setup/uninstall.cc
@@ -7,6 +7,8 @@
 #include <windows.h>
 #include <memory>
 
+#include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/process/launch.h"
@@ -14,18 +16,35 @@
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
+#include "base/win/scoped_com_initializer.h"
 #include "chrome/updater/updater_constants.h"
 #include "chrome/updater/util.h"
+#include "chrome/updater/win/setup/setup_util.h"
+#include "chrome/updater/win/task_scheduler.h"
 
 namespace updater {
 
-// Runs the uninstall script in the install directory of the updater. This is
-// a best effort uninstall. The execution of this function and the script race
-// each other but the script loops and wait in between iterations trying to
-// delete the install directory.
+// Reverses the changes made by setup. This is a best effort uninstall:
+// 1. deletes the scheduled task.
+// 2. runs the uninstall script in the install directory of the updater.
+// The execution of this function and the script race each other but the script
+// loops and waits in between iterations trying to delete the install directory.
 int Uninstall() {
   VLOG(1) << __func__;
 
+  auto scoped_com_initializer =
+      std::make_unique<base::win::ScopedCOMInitializer>(
+          base::win::ScopedCOMInitializer::kMTA);
+
+  if (!TaskScheduler::Initialize()) {
+    LOG(ERROR) << "Failed to initialize the scheduler.";
+    return -1;
+  }
+  base::ScopedClosureRunner task_scheduler_terminate_caller(
+      base::BindOnce([]() { TaskScheduler::Terminate(); }));
+
+  updater::UnregisterUpdateAppsTask();
+
   base::FilePath product_dir;
   if (!GetProductDirectory(&product_dir)) {
     LOG(ERROR) << "GetProductDirectory failed.";
diff --git a/chrome/updater/win/setup/uninstall.cmd b/chrome/updater/win/setup/uninstall.cmd
index 9f3ba4286..bbaf5ce6c 100644
--- a/chrome/updater/win/setup/uninstall.cmd
+++ b/chrome/updater/win/setup/uninstall.cmd
@@ -3,7 +3,7 @@
 rem delete the directory.

 @echo off

 set Directory=%~dp0

-@echo %Directory% | FindStr /R \\AppData\\Local\\ChromeUpdater\\ > nul

+@echo %Directory% | FindStr /R \\AppData\\Local\\Google\\GoogleUpdater\\ > nul

 IF %ERRORLEVEL% NEQ 0 exit 1

 @echo Deleting "%Directory%"...

 for /L %%G IN (1,1,3) do (

diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index 49ffb6f0..f101ca6 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -151,6 +151,10 @@
 const base::Feature kEnableGeneralAudienceBrowsing{
     "enable_general_audience_browsing", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Uses unified IPC QueryableData bindings backend instead of v8 injection.
+const base::Feature kUseQueryableDataBackend{"use_queryable_data_backend",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 // End Chromecast Feature definitions.
 const base::Feature* kFeatures[] = {
     &kAllowUserMediaAccess,
@@ -159,6 +163,7 @@
     &kSingleBuffer,
     &kDisableIdleSocketsCloseOnMemoryPressure,
     &kEnableGeneralAudienceBrowsing,
+    &kUseQueryableDataBackend,
 };
 
 // An iterator for a base::DictionaryValue. Use an alias for brevity in loops.
diff --git a/chromecast/base/cast_features.h b/chromecast/base/cast_features.h
index 6893eb8..8d1f0b5 100644
--- a/chromecast/base/cast_features.h
+++ b/chromecast/base/cast_features.h
@@ -29,6 +29,7 @@
 extern const base::Feature kSingleBuffer;
 extern const base::Feature kDisableIdleSocketsCloseOnMemoryPressure;
 extern const base::Feature kEnableGeneralAudienceBrowsing;
+extern const base::Feature kUseQueryableDataBackend;
 
 // Get an iterable list of all of the cast features for checking all features as
 // a collection.
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index 363f0c3..c67d352 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -10,6 +10,7 @@
 #include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
 #include "chromecast/base/bitstream_audio_codecs.h"
+#include "chromecast/base/cast_features.h"
 #include "chromecast/base/chromecast_switches.h"
 #include "chromecast/media/base/media_codec_support.h"
 #include "chromecast/media/base/supported_codec_profile_levels_memo.h"
@@ -169,7 +170,9 @@
   DCHECK(render_frame);
   // Lifetime is tied to |render_frame| via content::RenderFrameObserver.
   new CastMediaPlaybackOptions(render_frame);
-  new QueryableDataBindings(render_frame);
+  if (!::chromecast::IsFeatureEnabled(kUseQueryableDataBackend)) {
+    new QueryableDataBindings(render_frame);
+  }
 
   // Add script injection support to the RenderFrame, used by Cast platform
   // APIs. The objects' lifetimes are bound to the RenderFrame's lifetime.
diff --git a/chromeos/services/assistant/media_session/assistant_media_session.cc b/chromeos/services/assistant/media_session/assistant_media_session.cc
index d2c4708a..31bbbc9 100644
--- a/chromeos/services/assistant/media_session/assistant_media_session.cc
+++ b/chromeos/services/assistant/media_session/assistant_media_session.cc
@@ -141,9 +141,11 @@
     return;
 
   audio_focus_remote_.reset();
+
   client_->RequestAudioFocusManager(
       audio_focus_remote_.BindNewPipeAndPassReceiver());
-  audio_focus_remote_->SetSourceName(kAudioFocusSourceName);
+  audio_focus_remote_->SetSource(base::UnguessableToken::Create(),
+                                 kAudioFocusSourceName);
 }
 
 void AssistantMediaSession::FinishAudioFocusRequest(
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn
index ded826a..4780dbc 100644
--- a/chromeos/services/device_sync/BUILD.gn
+++ b/chromeos/services/device_sync/BUILD.gn
@@ -134,7 +134,6 @@
     "//chromeos/services/device_sync/public/mojom",
     "//components/signin/public/identity_manager",
     "//services/network/public/cpp",
-    "//services/service_manager/public/cpp",
   ]
 
   deps = [
@@ -150,12 +149,11 @@
     "//components/gcm_driver",
     "//net",
     "//services/preferences/public/cpp",
-    "//services/service_manager/public/cpp",
   ]
 
   visibility = [
     ":*",
-    "//chrome/browser",
+    "//chrome/browser/chromeos",
     "//chrome/test:test_support_ui",
     "//chromeos/services/device_sync/public/cpp:unit_tests",
   ]
@@ -275,7 +273,6 @@
     "//components/signin/public/identity_manager:test_support",
     "//net/traffic_annotation:test_support",
     "//services/network:test_support",
-    "//services/service_manager/public/cpp/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/chromeos/services/device_sync/DEPS b/chromeos/services/device_sync/DEPS
index c202c86..f8cf07c4 100644
--- a/chromeos/services/device_sync/DEPS
+++ b/chromeos/services/device_sync/DEPS
@@ -9,6 +9,5 @@
   "+services/network/public",
   "+services/network/test",
   "+services/preferences/public",
-  "+services/service_manager/public/cpp",
   "+components/cryptauth"
 ]
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index 64d50161..2941b0a 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -32,7 +32,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
 
@@ -219,15 +218,15 @@
 std::unique_ptr<DeviceSyncBase> DeviceSyncImpl::Factory::BuildInstance(
     signin::IdentityManager* identity_manager,
     gcm::GCMDriver* gcm_driver,
-    service_manager::Connector* connector,
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector,
     const GcmDeviceInfoProvider* gcm_device_info_provider,
     ClientAppMetadataProvider* client_app_metadata_provider,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     std::unique_ptr<base::OneShotTimer> timer) {
   return base::WrapUnique(new DeviceSyncImpl(
-      identity_manager, gcm_driver, connector, gcm_device_info_provider,
-      client_app_metadata_provider, std::move(url_loader_factory),
-      base::DefaultClock::GetInstance(),
+      identity_manager, gcm_driver, std::move(pref_store_connector),
+      gcm_device_info_provider, client_app_metadata_provider,
+      std::move(url_loader_factory), base::DefaultClock::GetInstance(),
       std::make_unique<PrefConnectionDelegate>(), std::move(timer)));
 }
 
@@ -239,13 +238,12 @@
 }
 
 void DeviceSyncImpl::PrefConnectionDelegate::ConnectToPrefService(
-    service_manager::Connector* connector,
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector,
     scoped_refptr<PrefRegistrySimple> pref_registry,
     prefs::ConnectCallback callback) {
-  prefs::mojom::PrefStoreConnectorPtr pref_store_connector;
-  connector->BindInterface(prefs::mojom::kServiceName, &pref_store_connector);
-  prefs::ConnectToPrefService(std::move(pref_store_connector),
-                              std::move(pref_registry), std::move(callback));
+  prefs::ConnectToPrefService(
+      prefs::mojom::PrefStoreConnectorPtr(std::move(pref_store_connector)),
+      std::move(pref_registry), std::move(callback));
 }
 
 DeviceSyncImpl::PendingSetSoftwareFeatureRequest::
@@ -302,7 +300,7 @@
 DeviceSyncImpl::DeviceSyncImpl(
     signin::IdentityManager* identity_manager,
     gcm::GCMDriver* gcm_driver,
-    service_manager::Connector* connector,
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector,
     const GcmDeviceInfoProvider* gcm_device_info_provider,
     ClientAppMetadataProvider* client_app_metadata_provider,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -312,7 +310,7 @@
     : DeviceSyncBase(),
       identity_manager_(identity_manager),
       gcm_driver_(gcm_driver),
-      connector_(connector),
+      pref_store_connector_(std::move(pref_store_connector)),
       gcm_device_info_provider_(gcm_device_info_provider),
       client_app_metadata_provider_(client_app_metadata_provider),
       url_loader_factory_(std::move(url_loader_factory)),
@@ -515,7 +513,6 @@
 
   identity_manager_ = nullptr;
   gcm_driver_ = nullptr;
-  connector_ = nullptr;
   gcm_device_info_provider_ = nullptr;
   client_app_metadata_provider_ = nullptr;
   url_loader_factory_ = nullptr;
@@ -546,7 +543,7 @@
 
   PA_LOG(VERBOSE) << "DeviceSyncImpl: Connecting to pref service.";
   pref_connection_delegate_->ConnectToPrefService(
-      connector_, std::move(pref_registry),
+      std::move(pref_store_connector_), std::move(pref_registry),
       base::Bind(&DeviceSyncImpl::OnConnectedToPrefService,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chromeos/services/device_sync/device_sync_impl.h b/chromeos/services/device_sync/device_sync_impl.h
index 4c38d7f..c6130e3 100644
--- a/chromeos/services/device_sync/device_sync_impl.h
+++ b/chromeos/services/device_sync/device_sync_impl.h
@@ -17,6 +17,8 @@
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
 #include "chromeos/services/device_sync/remote_device_provider.h"
 #include "components/signin/public/identity_manager/account_info.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/preferences/public/cpp/pref_service_factory.h"
 #include "services/preferences/public/mojom/preferences.mojom.h"
 
@@ -39,10 +41,6 @@
 class SharedURLLoaderFactory;
 }  // namespace network
 
-namespace service_manager {
-class Connector;
-}  // namespace service_manager
-
 namespace chromeos {
 
 namespace device_sync {
@@ -78,7 +76,8 @@
     virtual std::unique_ptr<DeviceSyncBase> BuildInstance(
         signin::IdentityManager* identity_manager,
         gcm::GCMDriver* gcm_driver,
-        service_manager::Connector* connector,
+        mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+            pref_store_conector,
         const GcmDeviceInfoProvider* gcm_device_info_provider,
         ClientAppMetadataProvider* client_app_metadata_provider,
         scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -131,7 +130,8 @@
 
     virtual scoped_refptr<PrefRegistrySimple> CreatePrefRegistry();
     virtual void ConnectToPrefService(
-        service_manager::Connector* connector,
+        mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+            pref_store_connector,
         scoped_refptr<PrefRegistrySimple> pref_registry,
         prefs::ConnectCallback callback);
   };
@@ -169,7 +169,8 @@
   DeviceSyncImpl(
       signin::IdentityManager* identity_manager,
       gcm::GCMDriver* gcm_driver,
-      service_manager::Connector* connector,
+      mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+          pref_store_connector,
       const GcmDeviceInfoProvider* gcm_device_info_provider,
       ClientAppMetadataProvider* client_app_metadata_provider,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -214,7 +215,7 @@
 
   signin::IdentityManager* identity_manager_;
   gcm::GCMDriver* gcm_driver_;
-  service_manager::Connector* connector_;
+  mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector_;
   const GcmDeviceInfoProvider* gcm_device_info_provider_;
   ClientAppMetadataProvider* client_app_metadata_provider_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
diff --git a/chromeos/services/device_sync/device_sync_service.cc b/chromeos/services/device_sync/device_sync_service.cc
index 7668765..7007fc5 100644
--- a/chromeos/services/device_sync/device_sync_service.cc
+++ b/chromeos/services/device_sync/device_sync_service.cc
@@ -21,8 +21,8 @@
     const GcmDeviceInfoProvider* gcm_device_info_provider,
     ClientAppMetadataProvider* client_app_metadata_provider,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)),
+    mojo::PendingReceiver<mojom::DeviceSyncServiceInitializer> init_receiver)
+    : init_receiver_(this, std::move(init_receiver)),
       identity_manager_(identity_manager),
       gcm_driver_(gcm_driver),
       gcm_device_info_provider_(gcm_device_info_provider),
@@ -37,25 +37,22 @@
     device_sync_->CloseAllBindings();
 }
 
-void DeviceSyncService::OnStart() {
-  PA_LOG(VERBOSE) << "DeviceSyncService::OnStart()";
-
+void DeviceSyncService::Initialize(
+    mojo::PendingReceiver<mojom::DeviceSyncService> receiver,
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+        pref_store_connector) {
+  PA_LOG(VERBOSE) << "DeviceSyncService::Init()";
+  receiver_.Bind(std::move(receiver));
   device_sync_ = DeviceSyncImpl::Factory::Get()->BuildInstance(
-      identity_manager_, gcm_driver_, service_binding_.GetConnector(),
+      identity_manager_, gcm_driver_, std::move(pref_store_connector),
       gcm_device_info_provider_, client_app_metadata_provider_,
       url_loader_factory_, std::make_unique<base::OneShotTimer>());
-
-  registry_.AddInterface(base::Bind(&DeviceSyncBase::BindRequest,
-                                    base::Unretained(device_sync_.get())));
 }
 
-void DeviceSyncService::OnBindInterface(
-    const service_manager::BindSourceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  PA_LOG(VERBOSE) << "DeviceSyncService::OnBindInterface() from interface "
-                  << interface_name << ".";
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
+void DeviceSyncService::BindDeviceSync(
+    mojo::PendingReceiver<mojom::DeviceSync> receiver) {
+  PA_LOG(VERBOSE) << "DeviceSyncService::BindDeviceSync()";
+  device_sync_->BindRequest(std::move(receiver));
 }
 
 }  // namespace device_sync
diff --git a/chromeos/services/device_sync/device_sync_service.h b/chromeos/services/device_sync/device_sync_service.h
index 5bdc208..7f4ab277 100644
--- a/chromeos/services/device_sync/device_sync_service.h
+++ b/chromeos/services/device_sync/device_sync_service.h
@@ -9,9 +9,8 @@
 
 #include "base/memory/ref_counted.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace gcm {
 class GCMDriver;
@@ -35,7 +34,8 @@
 
 // Service which provides an implementation for DeviceSync. This service creates
 // one implementation and shares it among all connection requests.
-class DeviceSyncService : public service_manager::Service {
+class DeviceSyncService : public mojom::DeviceSyncServiceInitializer,
+                          public mojom::DeviceSyncService {
  public:
   DeviceSyncService(
       signin::IdentityManager* identity_manager,
@@ -43,17 +43,21 @@
       const GcmDeviceInfoProvider* gcm_device_info_provider,
       ClientAppMetadataProvider* client_app_metadata_provider,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      service_manager::mojom::ServiceRequest request);
+      mojo::PendingReceiver<mojom::DeviceSyncServiceInitializer> init_receiver);
   ~DeviceSyncService() override;
 
  private:
-  // service_manager::Service:
-  void OnStart() override;
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
+  // mojom::DeviceSyncServiceInitializer:
+  void Initialize(mojo::PendingReceiver<mojom::DeviceSyncService> receiver,
+                  mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+                      pref_store_connector) override;
 
-  service_manager::ServiceBinding service_binding_;
+  // mojom::DeviceSyncService:
+  void BindDeviceSync(
+      mojo::PendingReceiver<mojom::DeviceSync> receiver) override;
+
+  mojo::Receiver<mojom::DeviceSyncServiceInitializer> init_receiver_;
+  mojo::Receiver<mojom::DeviceSyncService> receiver_{this};
 
   signin::IdentityManager* identity_manager_;
   gcm::GCMDriver* gcm_driver_;
@@ -62,7 +66,6 @@
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   std::unique_ptr<DeviceSyncBase> device_sync_;
-  service_manager::BinderRegistry registry_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceSyncService);
 };
diff --git a/chromeos/services/device_sync/device_sync_service_unittest.cc b/chromeos/services/device_sync/device_sync_service_unittest.cc
index e82bdc1..a4d0529 100644
--- a/chromeos/services/device_sync/device_sync_service_unittest.cc
+++ b/chromeos/services/device_sync/device_sync_service_unittest.cc
@@ -37,7 +37,6 @@
 #include "chromeos/services/device_sync/fake_software_feature_manager.h"
 #include "chromeos/services/device_sync/public/cpp/fake_client_app_metadata_provider.h"
 #include "chromeos/services/device_sync/public/cpp/fake_gcm_device_info_provider.h"
-#include "chromeos/services/device_sync/public/mojom/constants.mojom.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
 #include "chromeos/services/device_sync/remote_device_provider_impl.h"
 #include "chromeos/services/device_sync/software_feature_manager_impl.h"
@@ -46,7 +45,6 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -212,7 +210,8 @@
 
 class FakeCryptAuthSchedulerFactory : public CryptAuthSchedulerImpl::Factory {
  public:
-  FakeCryptAuthSchedulerFactory(TestingPrefServiceSimple* test_pref_service)
+  explicit FakeCryptAuthSchedulerFactory(
+      TestingPrefServiceSimple* test_pref_service)
       : test_pref_service_(test_pref_service) {}
 
   ~FakeCryptAuthSchedulerFactory() override = default;
@@ -532,9 +531,11 @@
       return test_pref_registry_;
     }
 
-    void ConnectToPrefService(service_manager::Connector* connector,
-                              scoped_refptr<PrefRegistrySimple> pref_registry,
-                              prefs::ConnectCallback callback) override {
+    void ConnectToPrefService(
+        mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+            pref_store_connector,
+        scoped_refptr<PrefRegistrySimple> pref_registry,
+        prefs::ConnectCallback callback) override {
       EXPECT_EQ(test_pref_service_->registry(), pref_registry.get());
       pending_callback_ = std::move(callback);
     }
@@ -564,16 +565,17 @@
     std::unique_ptr<DeviceSyncBase> BuildInstance(
         signin::IdentityManager* identity_manager,
         gcm::GCMDriver* gcm_driver,
-        service_manager::Connector* connector,
+        mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+            pref_store_connector,
         const GcmDeviceInfoProvider* gcm_device_info_provider,
         ClientAppMetadataProvider* client_app_metadata_provider,
         scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
         std::unique_ptr<base::OneShotTimer> timer) override {
       return base::WrapUnique(new DeviceSyncImpl(
-          identity_manager, gcm_driver, connector, gcm_device_info_provider,
-          client_app_metadata_provider, std::move(url_loader_factory),
-          simple_test_clock_, std::move(fake_pref_connection_delegate_),
-          std::move(mock_timer_)));
+          identity_manager, gcm_driver, std::move(pref_store_connector),
+          gcm_device_info_provider, client_app_metadata_provider,
+          std::move(url_loader_factory), simple_test_clock_,
+          std::move(fake_pref_connection_delegate_), std::move(mock_timer_)));
     }
 
    private:
@@ -699,11 +701,20 @@
             }));
 
     fake_device_sync_observer_ = std::make_unique<FakeDeviceSyncObserver>();
+    mojo::Remote<mojom::DeviceSyncServiceInitializer> initializer;
     service_ = std::make_unique<DeviceSyncService>(
         identity_test_environment_->identity_manager(), fake_gcm_driver_.get(),
         fake_gcm_device_info_provider_.get(),
         fake_client_app_metadata_provider_.get(), shared_url_loader_factory,
-        connector_factory_.RegisterInstance(mojom::kServiceName));
+        initializer.BindNewPipeAndPassReceiver());
+
+    // FakePrefConnectionDelegate precludes the service ever actually sending
+    // messages over this interface, so we provided the service with a
+    // bound but disconnected endpoint.
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector;
+    ignore_result(pref_store_connector.InitWithNewPipeAndPassReceiver());
+    initializer->Initialize(remote_service_.BindNewPipeAndPassReceiver(),
+                            std::move(pref_store_connector));
   }
 
   void TearDown() override {
@@ -735,8 +746,7 @@
               device_already_enrolled_in_cryptauth);
     }
 
-    connector_factory_.GetDefaultConnector()->BindInterface(mojom::kServiceName,
-                                                            &device_sync_);
+    remote_service_->BindDeviceSync(mojo::MakeRequest(&device_sync_));
 
     // Set |fake_device_sync_observer_|.
     CallAddObserver();
@@ -1164,8 +1174,8 @@
   std::unique_ptr<gcm::FakeGCMDriver> fake_gcm_driver_;
   std::unique_ptr<FakeGcmDeviceInfoProvider> fake_gcm_device_info_provider_;
 
-  service_manager::TestConnectorFactory connector_factory_;
   std::unique_ptr<DeviceSyncService> service_;
+  mojo::Remote<mojom::DeviceSyncService> remote_service_;
 
   bool device_already_enrolled_in_cryptauth_;
   bool last_force_enrollment_now_result_;
diff --git a/chromeos/services/device_sync/public/cpp/BUILD.gn b/chromeos/services/device_sync/public/cpp/BUILD.gn
index 87d5152e..8afb602 100644
--- a/chromeos/services/device_sync/public/cpp/BUILD.gn
+++ b/chromeos/services/device_sync/public/cpp/BUILD.gn
@@ -22,7 +22,6 @@
     "//chromeos/components/multidevice",
     "//chromeos/components/multidevice/logging",
     "//chromeos/services/device_sync/public/mojom",
-    "//services/service_manager/public/cpp",
   ]
 
   deps = [
@@ -73,21 +72,6 @@
     "//components/signin/public/identity_manager:test_support",
     "//net",
     "//services/network:test_support",
-    "//services/service_manager/public/cpp/test:test_support",
     "//testing/gtest",
   ]
 }
-
-source_set("manifest") {
-  sources = [
-    "manifest.cc",
-    "manifest.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chromeos/services/device_sync/public/mojom",
-    "//services/preferences/public/mojom",
-    "//services/service_manager/public/cpp",
-  ]
-}
diff --git a/chromeos/services/device_sync/public/cpp/OWNERS b/chromeos/services/device_sync/public/cpp/OWNERS
deleted file mode 100644
index 6faeaa47..0000000
--- a/chromeos/services/device_sync/public/cpp/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file manifest.cc=set noparent
-per-file manifest.cc=file://ipc/SECURITY_OWNERS
-per-file manifest.h=set noparent
-per-file manifest.h=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
index b1324e2..fea8439f 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
+++ b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.cc
@@ -13,9 +13,7 @@
 #include "chromeos/components/multidevice/expiring_remote_device_cache.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/remote_device.h"
-#include "chromeos/services/device_sync/public/mojom/constants.mojom.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
 
@@ -43,22 +41,21 @@
 DeviceSyncClientImpl::Factory::~Factory() = default;
 
 std::unique_ptr<DeviceSyncClient> DeviceSyncClientImpl::Factory::BuildInstance(
-    service_manager::Connector* connector) {
-  return base::WrapUnique(new DeviceSyncClientImpl(connector));
+    mojom::DeviceSyncService* service) {
+  return base::WrapUnique(new DeviceSyncClientImpl(service));
 }
 
-DeviceSyncClientImpl::DeviceSyncClientImpl(
-    service_manager::Connector* connector)
-    : DeviceSyncClientImpl(connector, base::ThreadTaskRunnerHandle::Get()) {}
+DeviceSyncClientImpl::DeviceSyncClientImpl(mojom::DeviceSyncService* service)
+    : DeviceSyncClientImpl(service, base::ThreadTaskRunnerHandle::Get()) {}
 
 DeviceSyncClientImpl::DeviceSyncClientImpl(
-    service_manager::Connector* connector,
+    mojom::DeviceSyncService* service,
     scoped_refptr<base::TaskRunner> task_runner)
     : binding_(this),
       expiring_device_cache_(
           std::make_unique<multidevice::ExpiringRemoteDeviceCache>()),
       weak_ptr_factory_(this) {
-  connector->BindInterface(mojom::kServiceName, &device_sync_ptr_);
+  service->BindDeviceSync(mojo::MakeRequest(&device_sync_ptr_));
   device_sync_ptr_->AddObserver(GenerateInterfacePtr(), base::OnceClosure());
 
   // Delay calling these until after the constructor finishes.
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.h b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.h
index 1eb80badf..0507eb15 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_client_impl.h
+++ b/chromeos/services/device_sync/public/cpp/device_sync_client_impl.h
@@ -24,10 +24,6 @@
 class TaskRunner;
 }  // namespace base
 
-namespace service_manager {
-class Connector;
-}  // namespace service_manager
-
 namespace chromeos {
 
 namespace multidevice {
@@ -46,13 +42,13 @@
     static void SetInstanceForTesting(Factory* test_factory);
     virtual ~Factory();
     virtual std::unique_ptr<DeviceSyncClient> BuildInstance(
-        service_manager::Connector* connector);
+        mojom::DeviceSyncService* service);
 
    private:
     static Factory* test_factory_;
   };
 
-  explicit DeviceSyncClientImpl(service_manager::Connector* connector);
+  explicit DeviceSyncClientImpl(mojom::DeviceSyncService* service);
   ~DeviceSyncClientImpl() override;
 
   // DeviceSyncClient:
@@ -79,7 +75,7 @@
  private:
   friend class DeviceSyncClientImplTest;
 
-  DeviceSyncClientImpl(service_manager::Connector* connector,
+  DeviceSyncClientImpl(mojom::DeviceSyncService* service,
                        scoped_refptr<base::TaskRunner> task_runner);
 
   void AttemptToBecomeReady();
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc b/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
index 0404f67..7bf57203 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
+++ b/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
@@ -23,12 +23,10 @@
 #include "chromeos/services/device_sync/fake_device_sync.h"
 #include "chromeos/services/device_sync/public/cpp/fake_client_app_metadata_provider.h"
 #include "chromeos/services/device_sync/public/cpp/fake_gcm_device_info_provider.h"
-#include "chromeos/services/device_sync/public/mojom/constants.mojom.h"
 #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
 #include "components/gcm_driver/fake_gcm_driver.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -63,7 +61,8 @@
   std::unique_ptr<DeviceSyncBase> BuildInstance(
       signin::IdentityManager* identity_manager,
       gcm::GCMDriver* gcm_driver,
-      service_manager::Connector* connector,
+      mojo::PendingRemote<prefs::mojom::PrefStoreConnector>
+          pref_store_connector,
       const GcmDeviceInfoProvider* gcm_device_info_provider,
       ClientAppMetadataProvider* client_app_metadata_provider,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -170,11 +169,17 @@
               return nullptr;
             }));
 
+    mojo::Remote<mojom::DeviceSyncServiceInitializer> initializer;
     service_ = std::make_unique<DeviceSyncService>(
         identity_test_environment_->identity_manager(), fake_gcm_driver_.get(),
         fake_gcm_device_info_provider_.get(),
         fake_client_app_metadata_provider_.get(), shared_url_loader_factory,
-        connector_factory_.RegisterInstance(mojom::kServiceName));
+        initializer.BindNewPipeAndPassReceiver());
+
+    mojo::PendingRemote<prefs::mojom::PrefStoreConnector> pref_store_connector;
+    ignore_result(pref_store_connector.InitWithNewPipeAndPassReceiver());
+    initializer->Initialize(remote_service_.BindNewPipeAndPassReceiver(),
+                            std::move(pref_store_connector));
 
     test_observer_ = std::make_unique<TestDeviceSyncClientObserver>();
 
@@ -185,8 +190,8 @@
     // DeviceSyncClient's constructor posts two tasks to the TaskRunner. Idle
     // the TaskRunner so that the tasks can be run via a RunLoop later on.
     auto test_task_runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
-    client_ = base::WrapUnique(new DeviceSyncClientImpl(
-        connector_factory_.GetDefaultConnector(), test_task_runner));
+    client_ = base::WrapUnique(
+        new DeviceSyncClientImpl(remote_service_.get(), test_task_runner));
     test_task_runner->RunUntilIdle();
   }
 
@@ -430,8 +435,8 @@
       fake_client_app_metadata_provider_;
   FakeDeviceSync* fake_device_sync_;
   std::unique_ptr<FakeDeviceSyncImplFactory> fake_device_sync_impl_factory_;
-  service_manager::TestConnectorFactory connector_factory_;
   std::unique_ptr<DeviceSyncService> service_;
+  mojo::Remote<mojom::DeviceSyncService> remote_service_;
   std::unique_ptr<TestDeviceSyncClientObserver> test_observer_;
 
   std::unique_ptr<DeviceSyncClientImpl> client_;
diff --git a/chromeos/services/device_sync/public/cpp/manifest.cc b/chromeos/services/device_sync/public/cpp/manifest.cc
deleted file mode 100644
index d2cdfa7..0000000
--- a/chromeos/services/device_sync/public/cpp/manifest.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/services/device_sync/public/cpp/manifest.h"
-
-#include "base/no_destructor.h"
-#include "chromeos/services/device_sync/public/mojom/constants.mojom.h"
-#include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
-#include "services/preferences/public/mojom/preferences.mojom.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-namespace chromeos {
-namespace device_sync {
-
-const service_manager::Manifest& GetManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .WithServiceName(mojom::kServiceName)
-          .WithDisplayName("DeviceSync Service")
-          .ExposeCapability(
-              "device_sync",
-              service_manager::Manifest::InterfaceList<mojom::DeviceSync>())
-          .RequireCapability(prefs::mojom::kServiceName, "pref_client")
-          .Build()};
-  return *manifest;
-}
-
-}  // namespace device_sync
-}  // namespace chromeos
diff --git a/chromeos/services/device_sync/public/cpp/manifest.h b/chromeos/services/device_sync/public/cpp/manifest.h
deleted file mode 100644
index 404c165..0000000
--- a/chromeos/services/device_sync/public/cpp/manifest.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_CPP_MANIFEST_H_
-#define CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_CPP_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-namespace chromeos {
-namespace device_sync {
-
-const service_manager::Manifest& GetManifest();
-
-}  // namespace device_sync
-}  // namespace chromeos
-
-#endif  // CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_CPP_MANIFEST_H_
diff --git a/chromeos/services/device_sync/public/mojom/BUILD.gn b/chromeos/services/device_sync/public/mojom/BUILD.gn
index 9a23615..8014769 100644
--- a/chromeos/services/device_sync/public/mojom/BUILD.gn
+++ b/chromeos/services/device_sync/public/mojom/BUILD.gn
@@ -6,12 +6,12 @@
 
 mojom("mojom") {
   sources = [
-    "constants.mojom",
     "device_sync.mojom",
   ]
 
   public_deps = [
     "//chromeos/components/multidevice/mojom",
     "//mojo/public/mojom/base",
+    "//services/preferences/public/mojom",
   ]
 }
diff --git a/chromeos/services/device_sync/public/mojom/constants.mojom b/chromeos/services/device_sync/public/mojom/constants.mojom
deleted file mode 100644
index 4b271906..0000000
--- a/chromeos/services/device_sync/public/mojom/constants.mojom
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module chromeos.device_sync.mojom;
-
-const string kServiceName = "device_sync";
diff --git a/chromeos/services/device_sync/public/mojom/device_sync.mojom b/chromeos/services/device_sync/public/mojom/device_sync.mojom
index 390aeca9..4f72d887 100644
--- a/chromeos/services/device_sync/public/mojom/device_sync.mojom
+++ b/chromeos/services/device_sync/public/mojom/device_sync.mojom
@@ -6,6 +6,7 @@
 
 import "chromeos/components/multidevice/mojom/multidevice_types.mojom";
 import "mojo/public/mojom/base/time.mojom";
+import "services/preferences/public/mojom/preferences.mojom";
 
 enum NetworkRequestResult {
   // Successful network request.
@@ -146,3 +147,20 @@
   //                  refactored out of DeviceSync.
   GetDebugInfo() => (DebugInfo? debug_info);
 };
+
+// The main interface to the Device Sync service, used to initialized a new
+// instance of the service.
+interface DeviceSyncServiceInitializer {
+  // Initializes the service instance, binding a DeviceSyncService endpoint
+  // with access to a given PrefStoreConnector.
+  Initialize(
+      pending_receiver<DeviceSyncService> receiver,
+      pending_remote<prefs.mojom.PrefStoreConnector> pref_store_connector);
+};
+
+// The main interface to the Device Sync service.
+interface DeviceSyncService {
+  // Binds a new DeviceSync endpoint.
+  BindDeviceSync(pending_receiver<DeviceSync> receiver);
+};
+
diff --git a/components/arc/media_session/arc_media_session_bridge.cc b/components/arc/media_session/arc_media_session_bridge.cc
index e5c0dbdf..a532ce0 100644
--- a/components/arc/media_session/arc_media_session_bridge.cc
+++ b/components/arc/media_session/arc_media_session_bridge.cc
@@ -91,7 +91,8 @@
   content::GetSystemConnector()->BindInterface(
       media_session::mojom::kServiceName, &audio_focus_ptr);
 
-  audio_focus_ptr->SetSourceName(kAudioFocusSourceName);
+  audio_focus_ptr->SetSource(base::UnguessableToken::Create(),
+                             kAudioFocusSourceName);
 
   DVLOG(2) << "ArcMediaSessionBridge will enable audio focus";
   ms_instance->EnableAudioFocus(std::move(audio_focus_ptr));
diff --git a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
index cdf3e44..e710401f 100644
--- a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
+++ b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
@@ -73,7 +73,7 @@
      * @param filePath File path of the download.
      * @return True if the download needs to be published, or false otherwise.
      */
-    protected boolean needToPublishDownload(final String filePath) {
+    public boolean needToPublishDownload(final String filePath) {
         return false;
     }
 
@@ -116,10 +116,12 @@
     }
 
     /**
-     * @return whether a download with the file name exists.
+     * Gets the content URI of the download that has the given file name.
+     * @param pendingUri name of the file.
+     * @return Uri of the download with the given display name.
      */
-    protected boolean checkFileNameExists(final String fileName) {
-        return false;
+    public Uri getDownloadUriForFileName(final String fileName) {
+        return null;
     }
 
     /**
@@ -251,7 +253,8 @@
      */
     @CalledByNative
     private static boolean fileNameExists(final String fileName) {
-        return getDownloadCollectionBridge().checkFileNameExists(fileName);
+        Uri uri = getDownloadCollectionBridge().getDownloadUriForFileName(fileName);
+        return uri != null;
     }
 
     /**
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index cf1d2aa..9b457c8 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -2424,13 +2424,6 @@
   download_params->set_referrer_policy(net::URLRequest::NEVER_CLEAR_REFERRER);
   download_params->set_follow_cross_origin_redirects(false);
 
-  // If the interruption was caused by content length mismatch, ignore it during
-  // resumption.
-  if (last_reason_ ==
-      DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH) {
-    download_params->set_ignore_content_length_mismatch(true);
-  }
-
   TransitionTo(RESUMING_INTERNAL);
   RecordDownloadCountWithSource(source == ResumptionRequestSource::USER
                                     ? MANUAL_RESUMPTION_COUNT
diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc
index 1d5e394..707c14ea 100644
--- a/components/download/internal/common/download_response_handler.cc
+++ b/components/download/internal/common/download_response_handler.cc
@@ -58,7 +58,6 @@
     const DownloadUrlParameters::RequestHeadersType& request_headers,
     const std::string& request_origin,
     DownloadSource download_source,
-    bool ignore_content_length_mismatch,
     std::vector<GURL> url_chain,
     bool is_background_mode)
     : delegate_(delegate),
@@ -75,7 +74,7 @@
       request_headers_(request_headers),
       request_origin_(request_origin),
       download_source_(download_source),
-      ignore_content_length_mismatch_(ignore_content_length_mismatch),
+      has_strong_validators_(false),
       is_partial_request_(save_info_->offset > 0),
       completed_(false),
       abort_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
@@ -98,15 +97,7 @@
   // Sets page transition type correctly and call
   // |RecordDownloadSourcePageTransitionType| here.
   if (head.headers) {
-    // ERR_CONTENT_LENGTH_MISMATCH can be caused by 1 of the following reasons:
-    // 1. Server or proxy closes the connection too early.
-    // 2. The content-length header is wrong.
-    // If the download has strong validators, we can interrupt the download
-    // and let it resume automatically. Otherwise, resuming the download will
-    // cause it to restart and the download may never complete if the error was
-    // caused by reason 2. As a result, downloads without strong validators are
-    // treated as completed here.
-    ignore_content_length_mismatch_ |= !head.headers->HasStrongValidators();
+    has_strong_validators_ = head.headers->HasStrongValidators();
     RecordDownloadHttpResponseCode(head.headers->response_code(),
                                    is_background_mode_);
     RecordDownloadContentDisposition(create_info_->content_disposition);
@@ -234,9 +225,8 @@
 
   completed_ = true;
   DownloadInterruptReason reason = HandleRequestCompletionStatus(
-      static_cast<net::Error>(status.error_code),
-      ignore_content_length_mismatch_, cert_status_, is_partial_request_,
-      abort_reason_);
+      static_cast<net::Error>(status.error_code), has_strong_validators_,
+      cert_status_, is_partial_request_, abort_reason_);
 
   if (client_ptr_) {
     client_ptr_->OnStreamCompleted(
diff --git a/components/download/internal/common/download_utils.cc b/components/download/internal/common/download_utils.cc
index 6ee818d..d9bcc7b5 100644
--- a/components/download/internal/common/download_utils.cc
+++ b/components/download/internal/common/download_utils.cc
@@ -53,12 +53,23 @@
 
 DownloadInterruptReason HandleRequestCompletionStatus(
     net::Error error_code,
-    bool ignore_content_length_mismatch,
+    bool has_strong_validators,
     net::CertStatus cert_status,
     bool is_partial_request,
     DownloadInterruptReason abort_reason) {
+  // ERR_CONTENT_LENGTH_MISMATCH can be caused by 1 of the following reasons:
+  // 1. Server or proxy closes the connection too early.
+  // 2. The content-length header is wrong.
+  // If the download has strong validators, we can interrupt the download
+  // and let it resume automatically. Otherwise, resuming the download will
+  // cause it to restart and the download may never complete if the error was
+  // caused by reason 2. As a result, downloads without strong validators are
+  // treated as completed here.
+  // TODO(qinmin): check the metrics from downloads with strong validators,
+  // and decide whether we should interrupt downloads without strong validators
+  // rather than complete them.
   if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH &&
-      ignore_content_length_mismatch) {
+      !has_strong_validators) {
     error_code = net::OK;
     RecordDownloadCount(COMPLETED_WITH_CONTENT_LENGTH_MISMATCH_COUNT);
   }
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index 3c49bd3a..f3a58f7 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -163,8 +163,8 @@
       download_url_parameters->request_headers(),
       download_url_parameters->request_origin(),
       download_url_parameters->download_source(),
-      download_url_parameters->ignore_content_length_mismatch(),
       std::vector<GURL>(1, resource_request_->url), is_background_mode);
+
   network::mojom::URLLoaderClientPtr url_loader_client_ptr;
   url_loader_client_binding_ =
       std::make_unique<mojo::Binding<network::mojom::URLLoaderClient>>(
@@ -203,8 +203,7 @@
       true,  /* follow_cross_origin_redirects */
       download::DownloadUrlParameters::RequestHeadersType(),
       std::string(), /* request_origin */
-      download::DownloadSource::NAVIGATION,
-      false /* ignore_content_length_mismatch */, std::move(url_chain),
+      download::DownloadSource::NAVIGATION, std::move(url_chain),
       false /* is_background_mode */);
 
   // Simulate on the new URLLoaderClient calls that happened on the old client.
diff --git a/components/download/public/common/download_response_handler.h b/components/download/public/common/download_response_handler.h
index 9b67e71a..b6f8ae3 100644
--- a/components/download/public/common/download_response_handler.h
+++ b/components/download/public/common/download_response_handler.h
@@ -52,7 +52,6 @@
       const DownloadUrlParameters::RequestHeadersType& request_headers,
       const std::string& request_origin,
       DownloadSource download_source,
-      bool ignore_content_length_mismatch,
       std::vector<GURL> url_chain,
       bool is_background_mode);
   ~DownloadResponseHandler() override;
@@ -97,7 +96,7 @@
   std::string request_origin_;
   DownloadSource download_source_;
   net::CertStatus cert_status_;
-  bool ignore_content_length_mismatch_;
+  bool has_strong_validators_;
   base::Optional<url::Origin> request_initiator_;
   bool is_partial_request_;
   bool completed_;
diff --git a/components/download/public/common/download_url_parameters.cc b/components/download/public/common/download_url_parameters.cc
index 0c85c8f..fd465914 100644
--- a/components/download/public/common/download_url_parameters.cc
+++ b/components/download/public/common/download_url_parameters.cc
@@ -40,8 +40,7 @@
       transient_(false),
       traffic_annotation_(traffic_annotation),
       download_source_(DownloadSource::UNKNOWN),
-      require_safety_checks_(true),
-      ignore_content_length_mismatch_(false) {}
+      require_safety_checks_(true) {}
 
 DownloadUrlParameters::~DownloadUrlParameters() = default;
 
diff --git a/components/download/public/common/download_url_parameters.h b/components/download/public/common/download_url_parameters.h
index ecbc0af..f276edd 100644
--- a/components/download/public/common/download_url_parameters.h
+++ b/components/download/public/common/download_url_parameters.h
@@ -257,11 +257,6 @@
     require_safety_checks_ = require_safety_checks;
   }
 
-  // Sets whether to ignore content length mismatch errors.
-  void set_ignore_content_length_mismatch(bool ignore_content_length_mismatch) {
-    ignore_content_length_mismatch_ = ignore_content_length_mismatch;
-  }
-
   const OnStartedCallback& callback() const { return callback_; }
   bool content_initiated() const { return content_initiated_; }
   const std::string& last_modified() const { return last_modified_; }
@@ -315,9 +310,6 @@
   bool is_transient() const { return transient_; }
   std::string guid() const { return guid_; }
   bool require_safety_checks() const { return require_safety_checks_; }
-  bool ignore_content_length_mismatch() const {
-    return ignore_content_length_mismatch_;
-  }
 
   // STATE CHANGING: All save_info_ sub-objects will be in an indeterminate
   // state following this call.
@@ -365,7 +357,6 @@
   DownloadSource download_source_;
   UploadProgressCallback upload_callback_;
   bool require_safety_checks_;
-  bool ignore_content_length_mismatch_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadUrlParameters);
 };
diff --git a/components/download/public/common/download_utils.h b/components/download/public/common/download_utils.h
index 69f4824..d48f61a 100644
--- a/components/download/public/common/download_utils.h
+++ b/components/download/public/common/download_utils.h
@@ -39,7 +39,7 @@
 // |cert_status| is ignored if error_code is not net::ERR_ABORTED.
 COMPONENTS_DOWNLOAD_EXPORT DownloadInterruptReason
 HandleRequestCompletionStatus(net::Error error_code,
-                              bool ignore_content_length_mismatch,
+                              bool has_strong_validators,
                               net::CertStatus cert_status,
                               bool is_partial_request,
                               DownloadInterruptReason abort_reason);
diff --git a/components/feed/core/feed_scheduler_host.cc b/components/feed/core/feed_scheduler_host.cc
index 05fb840..ee10d55 100644
--- a/components/feed/core/feed_scheduler_host.cc
+++ b/components/feed/core/feed_scheduler_host.cc
@@ -399,7 +399,9 @@
 }
 
 void FeedSchedulerHost::OnRequestError(int network_response_code) {
-  profile_prefs_->SetTime(prefs::kLastFetchAttemptTime, clock_->Now());
+  if (!kOnlySetLastRefreshAttemptOnSuccess.Get())
+    profile_prefs_->SetTime(prefs::kLastFetchAttemptTime, clock_->Now());
+
   last_fetch_status_ = network_response_code;
   TryRun(std::move(fixed_timer_completion_));
   outstanding_request_until_ = base::Time();
diff --git a/components/feed/core/feed_scheduler_host_unittest.cc b/components/feed/core/feed_scheduler_host_unittest.cc
index ece0df0..2a5bfbe 100644
--- a/components/feed/core/feed_scheduler_host_unittest.cc
+++ b/components/feed/core/feed_scheduler_host_unittest.cc
@@ -437,12 +437,23 @@
 }
 
 TEST_F(FeedSchedulerHostTest, OnRequestErrorVerifyPref) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      kInterestFeedContentSuggestions,
+      {{"only_set_last_refresh_attempt_on_success", "false"}});
+
   EXPECT_EQ(Time(), profile_prefs()->GetTime(prefs::kLastFetchAttemptTime));
   scheduler()->OnRequestError(0);
   EXPECT_EQ(test_clock()->Now(),
             profile_prefs()->GetTime(prefs::kLastFetchAttemptTime));
 }
 
+TEST_F(FeedSchedulerHostTest, OnRequestErrorVerifyRefreshTimeNotUpdated) {
+  EXPECT_EQ(Time(), profile_prefs()->GetTime(prefs::kLastFetchAttemptTime));
+  scheduler()->OnRequestError(0);
+  EXPECT_EQ(Time(), profile_prefs()->GetTime(prefs::kLastFetchAttemptTime));
+}
+
 TEST_F(FeedSchedulerHostTest, OnForegroundedActiveNtpUser) {
   scheduler()->OnForegrounded();
   EXPECT_EQ(1, refresh_call_count());
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc
index d91a45fd..0e48a1ce 100644
--- a/components/feed/feed_feature_list.cc
+++ b/components/feed/feed_feature_list.cc
@@ -17,6 +17,9 @@
     &kInterestFeedContentSuggestions, "timeout_duration_seconds", 30};
 const base::FeatureParam<bool> kThrottleBackgroundFetches{
     &kInterestFeedContentSuggestions, "throttle_background_fetches", true};
+const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess{
+    &kInterestFeedContentSuggestions,
+    "only_set_last_refresh_attempt_on_success", true};
 
 const base::Feature kInterestFeedNotifications{
     "InterestFeedNotifications", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index 8744609..41342be8 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -18,6 +18,7 @@
 extern const base::FeatureParam<int> kSuppressRefreshDurationMinutes;
 extern const base::FeatureParam<int> kTimeoutDurationSeconds;
 extern const base::FeatureParam<bool> kThrottleBackgroundFetches;
+extern const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess;
 
 extern const base::Feature kInterestFeedNotifications;
 
diff --git a/components/page_image_annotation/DEPS b/components/page_image_annotation/DEPS
index 3f62e9f..73bc2d5 100644
--- a/components/page_image_annotation/DEPS
+++ b/components/page_image_annotation/DEPS
@@ -2,6 +2,7 @@
   # Page image annotation is a layered component; subdirectories must explicitly
   # introduce the ability to use the content layer as appropriate.
   "-components/page_image_annotation/content",
+  "+mojo/public/cpp/bindings",
   "+services/image_annotation/public/mojom",
   "+services/image_annotation/public/cpp",
   "+services/service_manager/public/cpp",
diff --git a/components/page_image_annotation/content/renderer/DEPS b/components/page_image_annotation/content/renderer/DEPS
index 07132f3..8c0a429 100644
--- a/components/page_image_annotation/content/renderer/DEPS
+++ b/components/page_image_annotation/content/renderer/DEPS
@@ -2,6 +2,7 @@
   "+components/page_image_annotation/core",
   "+content/public/renderer",
   "+crypto",
+  "+third_party/blink/public/common/browser_interface_broker_proxy.h",
   "+third_party/blink/public/platform",
   "+third_party/blink/public/web",
   "+ui/base",
diff --git a/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc b/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc
index 098d757..10723fe 100644
--- a/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc
+++ b/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc
@@ -10,7 +10,7 @@
 #include "content/public/renderer/render_frame.h"
 #include "crypto/sha2.h"
 #include "services/image_annotation/public/mojom/image_annotation.mojom.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_local_frame.h"
@@ -40,11 +40,12 @@
   return PageAnnotator::ImageMetadata{node_id, source_id};
 }
 
-ia_mojom::AnnotatorPtr RequestAnnotator(
+mojo::PendingRemote<ia_mojom::Annotator> RequestAnnotator(
     content::RenderFrame* const render_frame) {
-  ia_mojom::AnnotatorPtr ptr;
-  render_frame->GetRemoteInterfaces()->GetInterface(mojo::MakeRequest(&ptr));
-  return ptr;
+  mojo::PendingRemote<ia_mojom::Annotator> annotator;
+  render_frame->GetBrowserInterfaceBrokerProxy()->GetInterface(
+      annotator.InitWithNewPipeAndPassReceiver());
+  return annotator;
 }
 
 }  // namespace
diff --git a/components/page_image_annotation/core/page_annotator.cc b/components/page_image_annotation/core/page_annotator.cc
index 90d148a..45927681 100644
--- a/components/page_image_annotation/core/page_annotator.cc
+++ b/components/page_image_annotation/core/page_annotator.cc
@@ -12,8 +12,8 @@
 
 PageAnnotator::Observer::~Observer() {}
 
-PageAnnotator::PageAnnotator(ia_mojom::AnnotatorPtr annotator_ptr)
-    : annotator_ptr_(std::move(annotator_ptr)) {}
+PageAnnotator::PageAnnotator(mojo::PendingRemote<ia_mojom::Annotator> annotator)
+    : annotator_(std::move(annotator)) {}
 
 PageAnnotator::~PageAnnotator() {}
 
@@ -59,7 +59,7 @@
     return;
 
   // TODO(crbug.com/916363): get a user's preferred language and pass it here.
-  annotator_ptr_->AnnotateImage(
+  annotator_->AnnotateImage(
       lookup->second.first.source_id,
       std::string() /* description_language_tag */,
       lookup->second.second.GetPtr(),
diff --git a/components/page_image_annotation/core/page_annotator.h b/components/page_image_annotation/core/page_annotator.h
index e36115a..e0854ab1 100644
--- a/components/page_image_annotation/core/page_annotator.h
+++ b/components/page_image_annotation/core/page_annotator.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/image_annotation/public/cpp/image_processor.h"
 #include "services/image_annotation/public/mojom/image_annotation.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -66,7 +67,8 @@
         image_annotation::mojom::AnnotateImageResultPtr result) = 0;
   };
 
-  explicit PageAnnotator(image_annotation::mojom::AnnotatorPtr annotator_ptr);
+  explicit PageAnnotator(
+      mojo::PendingRemote<image_annotation::mojom::Annotator> annotator);
   ~PageAnnotator();
 
   // Request annotation of the given image via the image annotation service.
@@ -101,7 +103,7 @@
                       uint64_t node_id,
                       image_annotation::mojom::AnnotateImageResultPtr result);
 
-  image_annotation::mojom::AnnotatorPtr annotator_ptr_;
+  mojo::Remote<image_annotation::mojom::Annotator> annotator_;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/components/page_image_annotation/core/page_annotator_unittest.cc b/components/page_image_annotation/core/page_annotator_unittest.cc
index f56ae3b3..2630345 100644
--- a/components/page_image_annotation/core/page_annotator_unittest.cc
+++ b/components/page_image_annotation/core/page_annotator_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/test/scoped_task_environment.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -49,10 +50,10 @@
 // AnnotateImage method was called.
 class TestAnnotator : public ia_mojom::Annotator {
  public:
-  ia_mojom::AnnotatorPtr GetPtr() {
-    ia_mojom::AnnotatorPtr ptr;
-    bindings_.AddBinding(this, mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<ia_mojom::Annotator> GetRemote() {
+    mojo::PendingRemote<ia_mojom::Annotator> remote;
+    receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
+    return remote;
   }
 
   void AnnotateImage(const std::string& source_id,
@@ -81,7 +82,7 @@
     image_processors_[index].reset();
   }
 
-  mojo::BindingSet<ia_mojom::Annotator> bindings_;
+  mojo::ReceiverSet<ia_mojom::Annotator> receivers_;
 };
 
 // Tests that correct image tracking messages are sent to observers.
@@ -90,7 +91,7 @@
 
   base::test::ScopedTaskEnvironment test_task_env;
 
-  PageAnnotator page_annotator(ia_mojom::AnnotatorPtr{});
+  PageAnnotator page_annotator((mojo::NullRemote()));
 
   MockObserver o1;
   page_annotator.AddObserver(&o1);
@@ -121,7 +122,7 @@
   base::test::ScopedTaskEnvironment test_task_env;
 
   TestAnnotator test_annotator;
-  PageAnnotator page_annotator(test_annotator.GetPtr());
+  PageAnnotator page_annotator(test_annotator.GetRemote());
   test_task_env.RunUntilIdle();
 
   // We use NiceMocks here since we don't place expectations on image added /
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
index b1afb41..124ec31d 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -100,6 +100,16 @@
   return std::string();
 }
 
+std::string CipherReEncrypt(const std::string& already_encrypted,
+                            std::string* key) {
+  using ::private_join_and_compute::ECCommutativeCipher;
+  auto cipher = ECCommutativeCipher::CreateWithNewKey(
+      NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
+  *key = cipher.ValueOrDie()->GetPrivateKeyBytes();
+  auto result = cipher.ValueOrDie()->ReEncrypt(already_encrypted);
+  return result.ValueOrDie();
+}
+
 std::string CipherDecrypt(const std::string& ciphertext,
                           const std::string& key) {
   using ::private_join_and_compute::ECCommutativeCipher;
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.h b/components/password_manager/core/browser/leak_detection/encryption_utils.h
index 88b1d53..fe7d90d 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils.h
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils.h
@@ -35,13 +35,22 @@
 // Encrypt/decrypt routines.
 
 // Encrypts |plaintext| with a new key. The key is returned via |key|.
+// Internally the function does some hashing first and then encrypts the result.
 std::string CipherEncrypt(const std::string& plaintext, std::string* key);
 
 // Encrypts |plaintext| with the existing key.
 std::string CipherEncryptWithKey(const std::string& plaintext,
                                  const std::string& key);
 
-// Decrypts |ciphertext| using |key|.
+// |already_encrypted| is an already encrypted string (output of CipherEncrypt).
+// Encrypts it again with a new key. The key is returned in |key|.
+// The function is different from CipherEncrypt() as it doesn't apply hashing on
+// the input.
+std::string CipherReEncrypt(const std::string& already_encrypted,
+                            std::string* key);
+
+// Decrypts |ciphertext| using |key|. The result isn't the original string but a
+// hash of it.
 std::string CipherDecrypt(const std::string& ciphertext,
                           const std::string& key);
 
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc b/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
index 322d92fe..30613dcc 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
@@ -29,18 +29,6 @@
   return point.ValueOrDie().ToBytesCompressed().ValueOrDie();
 }
 
-// |already_encrypted| is an already encrypted string (output of CipherEncrypt).
-// Encrypts it again with a new key. The key is returned in |key|.
-std::string CipherReEncrypt(const std::string& already_encrypted,
-                            std::string* key) {
-  using ::private_join_and_compute::ECCommutativeCipher;
-  auto cipher = ECCommutativeCipher::CreateWithNewKey(
-      NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
-  *key = cipher.ValueOrDie()->GetPrivateKeyBytes();
-  auto result = cipher.ValueOrDie()->ReEncrypt(already_encrypted);
-  return result.ValueOrDie();
-}
-
 // Converts a string to an array for printing.
 std::vector<int> StringAsArray(const std::string& s) {
   return std::vector<int>(s.begin(), s.end());
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
index 1884768..f03aa42 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -8,9 +8,11 @@
 
 #include "base/containers/span.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
 #include "components/password_manager/core/browser/leak_detection/single_lookup_response.h"
+#include "crypto/sha2.h"
 
 namespace password_manager {
 namespace {
@@ -26,6 +28,31 @@
   return data;
 }
 
+// Searches |reencrypted_lookup_hash| in the |encrypted_leak_match_prefixes|
+// array. |encryption_key| is the original client key used to encrypt the
+// payload.
+bool CheckIfCredentialWasLeaked(std::unique_ptr<SingleLookupResponse> response,
+                                const std::string& encryption_key) {
+  std::string decrypted_username_password =
+      CipherDecrypt(response->reencrypted_lookup_hash, encryption_key);
+  if (decrypted_username_password.empty()) {
+    DLOG(ERROR) << "Can't decrypt data="
+                << base::HexEncode(base::as_bytes(
+                       base::make_span(response->reencrypted_lookup_hash)));
+    return false;
+  }
+
+  std::string hash_username_password =
+      crypto::SHA256HashString(decrypted_username_password);
+
+  return std::any_of(response->encrypted_leak_match_prefixes.begin(),
+                     response->encrypted_leak_match_prefixes.end(),
+                     [&hash_username_password](const std::string& prefix) {
+                       return base::StartsWith(hash_username_password, prefix,
+                                               base::CompareCase::SENSITIVE);
+                     });
+}
+
 }  // namespace
 
 void PrepareSingleLeakRequestData(const std::string& username,
@@ -39,6 +66,18 @@
       std::move(callback));
 }
 
+void AnalyzeResponseResult(std::unique_ptr<SingleLookupResponse> response,
+                           const std::string& encryption_key,
+                           SingleLeakResponseAnalysisCallback callback) {
+  base::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::ThreadPool(), base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&CheckIfCredentialWasLeaked, std::move(response),
+                     encryption_key),
+      std::move(callback));
+}
+
 bool ParseLookupSingleLeakResponse(const SingleLookupResponse& response) {
   // TODO(crbug.com/086298): Implement decrypting the response and checking
   // whether the credential was actually leaked.
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
index 5be6770..94c3fe6 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
@@ -31,6 +31,8 @@
 using SingleLeakRequestDataCallback =
     base::OnceCallback<void(LookupSingleLeakData)>;
 
+using SingleLeakResponseAnalysisCallback = base::OnceCallback<void(bool)>;
+
 // Asynchronously creates a data payload for single credential check.
 // Callback is invoked on the calling thread with the protobuf and the
 // encryption key used.
@@ -38,6 +40,12 @@
                                   const std::string& password,
                                   SingleLeakRequestDataCallback callback);
 
+// Analyses the |response| asynchronously and checks if the credential was
+// leaked. |callback| is invoked on the calling thread.
+void AnalyzeResponseResult(std::unique_ptr<SingleLookupResponse> response,
+                           const std::string& encryption_key,
+                           SingleLeakResponseAnalysisCallback callback);
+
 // Processes the provided |response| and returns whether the relevant credential
 // was leaked.
 bool ParseLookupSingleLeakResponse(const SingleLookupResponse& response);
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
index 802bd600..3d8aee0e 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
@@ -6,15 +6,26 @@
 
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
+#include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_api.pb.h"
+#include "components/password_manager/core/browser/leak_detection/single_lookup_response.h"
+#include "crypto/sha2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
+namespace {
 
 using ::testing::ElementsAre;
 using ::testing::Field;
 
+// Converts a string to an array for printing.
+std::vector<int> StringToArray(const std::string& s) {
+  return std::vector<int>(s.begin(), s.end());
+}
+
+}  // namespace
+
 TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestData) {
   base::test::ScopedTaskEnvironment task_env;
   base::MockCallback<SingleLeakRequestDataCallback> callback;
@@ -30,4 +41,65 @@
   task_env.RunUntilIdle();
 }
 
+TEST(LeakDetectionRequestUtils, AnalyzeResponseResult_NoLeak) {
+  base::test::ScopedTaskEnvironment task_env;
+
+  constexpr char kUsernamePasswordHash[] = "abcdefg";
+  auto response = std::make_unique<SingleLookupResponse>();
+  std::string key_client;
+  std::string encrypted_username_password =
+      CipherEncrypt(kUsernamePasswordHash, &key_client);
+  std::string key_server;
+  response->reencrypted_lookup_hash =
+      CipherReEncrypt(encrypted_username_password, &key_server);
+  SCOPED_TRACE(testing::Message()
+               << "key_client="
+               << testing::PrintToString(StringToArray(key_client))
+               << ", key_server="
+               << testing::PrintToString(StringToArray(key_server)));
+
+  response->encrypted_leak_match_prefixes.push_back(crypto::SHA256HashString(
+      CipherEncryptWithKey("unrelated_trash", key_server)));
+
+  base::MockCallback<SingleLeakResponseAnalysisCallback> callback;
+
+  AnalyzeResponseResult(std::move(response), key_client, callback.Get());
+  EXPECT_CALL(callback, Run(false));
+  task_env.RunUntilIdle();
+}
+
+TEST(LeakDetectionRequestUtils, AnalyzeResponseResult_Leak) {
+  base::test::ScopedTaskEnvironment task_env;
+
+  constexpr char kUsernamePasswordHash[] = "abcdefg";
+  auto response = std::make_unique<SingleLookupResponse>();
+  std::string key_client;
+  std::string encrypted_username_password =
+      CipherEncrypt(kUsernamePasswordHash, &key_client);
+  std::string key_server;
+  response->reencrypted_lookup_hash =
+      CipherReEncrypt(encrypted_username_password, &key_server);
+  SCOPED_TRACE(testing::Message()
+               << "key_client="
+               << testing::PrintToString(StringToArray(key_client))
+               << ", key_server="
+               << testing::PrintToString(StringToArray(key_server)));
+
+  // Random length of the prefix for values in |encrypted_leak_match_prefixes|.
+  // The server can pick any value.
+  constexpr int kPrefixLength = 30;
+  response->encrypted_leak_match_prefixes.push_back(crypto::SHA256HashString(
+      CipherEncryptWithKey("unrelated_trash", key_server)));
+  response->encrypted_leak_match_prefixes.push_back(
+      crypto::SHA256HashString(
+          CipherEncryptWithKey(kUsernamePasswordHash, key_server))
+          .substr(0, kPrefixLength));
+
+  base::MockCallback<SingleLeakResponseAnalysisCallback> callback;
+
+  AnalyzeResponseResult(std::move(response), key_client, callback.Get());
+  EXPECT_CALL(callback, Run(true));
+  task_env.RunUntilIdle();
+}
+
 }  // namespace password_manager
diff --git a/components/safe_browsing/base_ui_manager.cc b/components/safe_browsing/base_ui_manager.cc
index 06c90f9..4118763 100644
--- a/components/safe_browsing/base_ui_manager.cc
+++ b/components/safe_browsing/base_ui_manager.cc
@@ -240,9 +240,12 @@
                        resource.web_contents_getter.Run(),
                        true /* A decision is now pending */,
                        resource.threat_type);
-  if (SafeBrowsingInterstitialsAreCommittedNavigations() &&
-      resource.IsMainPageLoadBlocked()) {
-    AddUnsafeResource(resource.url, resource);
+  if (SafeBrowsingInterstitialsAreCommittedNavigations()) {
+    GURL unsafe_url = (resource.IsMainPageLoadBlocked() ||
+                       !resource.GetNavigationEntryForResource())
+                          ? resource.url
+                          : resource.GetNavigationEntryForResource()->GetURL();
+    AddUnsafeResource(unsafe_url, resource);
     // With committed interstitials we just cancel the load from here, the
     // actual interstitial will be shown from the
     // SafeBrowsingNavigationThrottle.
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index 628810a..2490a4a 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -269,9 +269,7 @@
 
 void PasswordProtectionRequest::OnGetDomFeatures(const std::string& verdict) {
   ClientPhishingRequest dom_features_request;
-  bool parsed = dom_features_request.ParseFromString(verdict);
-  UMA_HISTOGRAM_BOOLEAN("PasswordProtection.DomFeatureParsing", parsed);
-  if (parsed) {
+  if (dom_features_request.ParseFromString(verdict)) {
     for (const ClientPhishingRequest::Feature& feature :
          dom_features_request.feature_map()) {
       DomFeatures::Feature* new_feature =
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index a7a1e4f..c6cd7b43 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -170,29 +170,30 @@
     const std::vector<std::string>& matching_domains,
     bool password_field_exists) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!IsSupportedPasswordTypeForPinging(password_type))
-    return;
-
-  // Collect metrics about typical page-zoom on login pages.
-  double zoom_level =
-      zoom::ZoomController::GetZoomLevelForWebContents(web_contents);
-  UMA_HISTOGRAM_COUNTS_1000(
-      "PasswordProtection.PageZoomFactor",
-      static_cast<int>(100 * content::ZoomLevelToZoomFactor(zoom_level)));
-
   ReusedPasswordAccountType reused_password_account_type =
       GetPasswordProtectionReusedPasswordAccountType(password_type, username);
   RequestOutcome reason;
-  if (CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                  main_frame_url, reused_password_account_type, &reason)) {
-    StartRequest(web_contents, main_frame_url, GURL(), GURL(), username,
-                 password_type, matching_domains,
-                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                 password_field_exists);
-  } else {
-    if (reused_password_account_type.is_account_syncing())
-      MaybeLogPasswordReuseLookupEvent(web_contents, reason, password_type,
-                                       nullptr);
+  // Need to populate |reason| to be passed into CanShowInterstitial.
+  bool can_send_ping =
+      CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                  main_frame_url, reused_password_account_type, &reason);
+  if (IsSupportedPasswordTypeForPinging(password_type)) {
+    // Collect metrics about typical page-zoom on login pages.
+    double zoom_level =
+        zoom::ZoomController::GetZoomLevelForWebContents(web_contents);
+    UMA_HISTOGRAM_COUNTS_1000(
+        "PasswordProtection.PageZoomFactor",
+        static_cast<int>(100 * content::ZoomLevelToZoomFactor(zoom_level)));
+    if (can_send_ping) {
+      StartRequest(web_contents, main_frame_url, GURL(), GURL(), username,
+                   password_type, matching_domains,
+                   LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                   password_field_exists);
+    } else {
+      if (reused_password_account_type.is_account_syncing())
+        MaybeLogPasswordReuseLookupEvent(web_contents, reason, password_type,
+                                         nullptr);
+    }
   }
   if (CanShowInterstitial(reason, reused_password_account_type,
                           main_frame_url)) {
@@ -246,6 +247,15 @@
       return;
     }
 
+    // If it's password alert mode and a Gsuite/enterprise account, we do not
+    // show a modal warning.
+    if (outcome == RequestOutcome::PASSWORD_ALERT_MODE &&
+        (password_type.account_type() == ReusedPasswordAccountType::GSUITE ||
+         password_type.account_type() ==
+             ReusedPasswordAccountType::NON_GAIA_ENTERPRISE)) {
+      return;
+    }
+
     if (ShouldShowModalWarning(request->trigger_type(), password_type,
                                response->verdict_type())) {
       username_ = request->username();
diff --git a/components/ui_devtools/css_agent_unittest.cc b/components/ui_devtools/css_agent_unittest.cc
index ad108885..fbbbedb1 100644
--- a/components/ui_devtools/css_agent_unittest.cc
+++ b/components/ui_devtools/css_agent_unittest.cc
@@ -316,18 +316,16 @@
   EXPECT_EQ(2, GetStyleSheetChangedCount(another_element_stylesheet_id));
 }
 
-TEST_F(CSSAgentTest, DISABLED_GetSource) {
+TEST_F(CSSAgentTest, GetSource) {
+  // Tests CSSAgent::getStyleSheetText() with one source file.
   std::string file = "components/test/data/ui_devtools/test_file.cc";
   element()->AddSource(file, 0);
   auto result = GetSourceForElement();
 
+  // Ensure that test_file.cc was read in correctly.
   EXPECT_TRUE(result.first);
-
-  std::string source_code;
-  DCHECK(GetSourceCode(file, &source_code));
-  DCHECK(source_code != "");
-
-  EXPECT_EQ(result.second, source_code);
+  EXPECT_NE(std::string::npos,
+            result.second.find("This file is for testing GetSource."));
 }
 
 TEST_F(CSSAgentTest, BadPathFails) {
diff --git a/components/ui_devtools/dom_agent.cc b/components/ui_devtools/dom_agent.cc
index 0036420..6eee0eba 100644
--- a/components/ui_devtools/dom_agent.cc
+++ b/components/ui_devtools/dom_agent.cc
@@ -160,7 +160,7 @@
   auto iter = std::find(children.begin(), children.end(), child);
   int prev_node_id =
       (iter == children.begin()) ? 0 : (*std::prev(iter))->node_id();
-  RemoveDomNode(child);
+  RemoveDomNode(child, false);
   frontend()->childNodeInserted(parent->node_id(), prev_node_id,
                                 BuildDomNodeFromUIElement(child));
 }
@@ -168,8 +168,7 @@
 void DOMAgent::OnUIElementRemoved(UIElement* ui_element) {
   DCHECK(node_id_to_ui_element_.count(ui_element->node_id()));
 
-  RemoveDomNode(ui_element);
-  node_id_to_ui_element_.erase(ui_element->node_id());
+  RemoveDomNode(ui_element, true);
 }
 
 void DOMAgent::OnUIElementBoundsChanged(UIElement* ui_element) {
@@ -250,11 +249,14 @@
     observer.OnElementBoundsChanged(ui_element);
 }
 
-void DOMAgent::RemoveDomNode(UIElement* ui_element) {
+void DOMAgent::RemoveDomNode(UIElement* ui_element, bool update_node_id_map) {
   for (auto* child_element : ui_element->children())
-    RemoveDomNode(child_element);
+    RemoveDomNode(child_element, update_node_id_map);
   frontend()->childNodeRemoved(ui_element->parent()->node_id(),
                                ui_element->node_id());
+  if (update_node_id_map) {
+    node_id_to_ui_element_.erase(ui_element->node_id());
+  }
 }
 
 void DOMAgent::Reset() {
diff --git a/components/ui_devtools/dom_agent.h b/components/ui_devtools/dom_agent.h
index a46788f..2b06a42 100644
--- a/components/ui_devtools/dom_agent.h
+++ b/components/ui_devtools/dom_agent.h
@@ -89,7 +89,11 @@
       UIElement* ui_element) = 0;
 
   void OnElementBoundsChanged(UIElement* ui_element);
-  void RemoveDomNode(UIElement* ui_element);
+
+  // Recursively removes |ui_element| and its children from the frontend
+  // elements tree. If |update_node_id_map|=true, also remove |ui_element|'s
+  // |node_id| from |node_id_to_ui_element_|.
+  void RemoveDomNode(UIElement* ui_element, bool update_node_id_map);
   void Reset();
   Query PreprocessQuery(protocol::String query);
   void SearchDomTree(const Query& query, std::vector<int>* result_collector);
diff --git a/components/ui_devtools/views/BUILD.gn b/components/ui_devtools/views/BUILD.gn
index 8a422954..e9fb3b2 100644
--- a/components/ui_devtools/views/BUILD.gn
+++ b/components/ui_devtools/views/BUILD.gn
@@ -29,6 +29,7 @@
 
   deps = [
     "//components/ui_devtools",
+    "//extensions/common",
     "//skia",
     "//ui/views",
   ]
diff --git a/components/ui_devtools/views/DEPS b/components/ui_devtools/views/DEPS
index f97255e..7484cad79 100644
--- a/components/ui_devtools/views/DEPS
+++ b/components/ui_devtools/views/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+extensions/common/image_util.h",
   "+third_party/skia/include",
   "+ui"
 ]
diff --git a/components/ui_devtools/views/dom_agent_unittest.cc b/components/ui_devtools/views/dom_agent_unittest.cc
index a6905a4..e539d20f 100644
--- a/components/ui_devtools/views/dom_agent_unittest.cc
+++ b/components/ui_devtools/views/dom_agent_unittest.cc
@@ -557,6 +557,60 @@
   EXPECT_TRUE(WasChildNodeInserted(target_view));
 }
 
+TEST_F(DOMAgentTest, NodeIdToUIElementTest) {
+  // widget
+  //   root_view
+  //     child_a1
+  //       child_a11
+  //         child_a111
+  //           child_a1111
+  //         child_a112
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
+
+  widget->Show();
+  views::View* root_view = widget->GetRootView();
+  views::View* child_a1 =
+      root_view->AddChildView(std::make_unique<views::View>());
+  views::View* child_a11 =
+      child_a1->AddChildView(std::make_unique<views::View>());
+  views::View* child_a111 =
+      child_a11->AddChildView(std::make_unique<views::View>());
+  views::View* child_a112 =
+      child_a11->AddChildView(std::make_unique<views::View>());
+  views::View* child_a1111 =
+      child_a111->AddChildView(std::make_unique<views::View>());
+
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int child_a1_id = GetIDForBackendElement(child_a1);
+  int child_a11_id = GetIDForBackendElement(child_a11);
+  int child_a111_id = GetIDForBackendElement(child_a111);
+  int child_a112_id = GetIDForBackendElement(child_a112);
+  int child_a1111_id = GetIDForBackendElement(child_a1111);
+
+  // Make sure all child nodes are in the |node_id_to_ui_element_| map.
+  EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a1_id), nullptr);
+  EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a11_id), nullptr);
+  EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a111_id), nullptr);
+  EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a112_id), nullptr);
+  EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a1111_id), nullptr);
+
+  root_view->RemoveChildView(child_a1);
+
+  // Check that child_a1 and its children are all removed from the
+  // |node_id_to_ui_element_| map.
+  EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a1_id), nullptr);
+  EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a11_id), nullptr);
+  EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a111_id), nullptr);
+  EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a112_id), nullptr);
+  EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a1111_id), nullptr);
+
+  // Required since it was removed from its parent view.
+  delete child_a1;
+}
+
 // Tests to ensure dom search for native UI is working
 TEST_F(DOMAgentTest, SimpleDomSearch) {
   std::unique_ptr<views::Widget> widget_a(
diff --git a/components/ui_devtools/views/element_utility.cc b/components/ui_devtools/views/element_utility.cc
index eb1eef6d..db30ea8 100644
--- a/components/ui_devtools/views/element_utility.cc
+++ b/components/ui_devtools/views/element_utility.cc
@@ -5,6 +5,8 @@
 #include "components/ui_devtools/views/element_utility.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "extensions/common/image_util.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/layer_owner.h"
 
 namespace ui_devtools {
@@ -50,4 +52,14 @@
   }
 }
 
+bool ParseColorFromFrontend(const std::string& input, std::string* output) {
+  std::string value;
+  base::TrimWhitespaceASCII(input, base::TRIM_ALL, &value);
+  SkColor color;
+  if (!extensions::image_util::ParseCssColorString(value, &color))
+    return false;
+  *output = base::NumberToString(color);
+  return true;
+}
+
 }  // namespace ui_devtools
diff --git a/components/ui_devtools/views/element_utility.h b/components/ui_devtools/views/element_utility.h
index 7aa19a1f..0423eb84 100644
--- a/components/ui_devtools/views/element_utility.h
+++ b/components/ui_devtools/views/element_utility.h
@@ -24,6 +24,11 @@
 void AppendLayerPropertiesMatchedStyle(const ui::Layer* layer,
                                        std::vector<UIElement::UIProperty>* ret);
 
+// Takes in color property from DevTools frontend as string in rgba()/rgb(),
+// hex, or hsla()/hsl() format and sets |output| to the SkColor value as a
+// string. Returns true if successful.
+bool ParseColorFromFrontend(const std::string& input, std::string* output);
+
 }  // namespace ui_devtools
 
 #endif  // COMPONENTS_UI_DEVTOOLS_VIEWS_ELEMENT_UTILITY_H_
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc
index 69886d2f..6115ce9 100644
--- a/components/ui_devtools/views/view_element.cc
+++ b/components/ui_devtools/views/view_element.cc
@@ -9,10 +9,30 @@
 #include "components/ui_devtools/Protocol.h"
 #include "components/ui_devtools/ui_element_delegate.h"
 #include "components/ui_devtools/views/element_utility.h"
+#include "ui/gfx/color_utils.h"
 #include "ui/views/widget/widget.h"
 
 namespace ui_devtools {
 
+namespace {
+
+// Returns true if |property_name| is type SkColor, false if not. If type
+// SkColor, remove the "--" from the name.
+bool GetSkColorPropertyName(std::string& property_name) {
+  if (property_name.length() < 2U)
+    return false;
+
+  // Check if property starts with "--", meaning its type is SkColor.
+  if (property_name[0] == '-' && property_name[1] == '-') {
+    // Remove "--" from |property_name|.
+    base::TrimString(property_name, "-", &property_name);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
 ViewElement::ViewElement(views::View* view,
                          UIElementDelegate* ui_element_delegate,
                          UIElement* parent)
@@ -90,9 +110,19 @@
                                       base::UTF16ToUTF8(description));
     }
 
-    class_properties.emplace_back(
-        (*member)->member_name(),
-        base::UTF16ToUTF8((*member)->GetValueAsString(view_)));
+    // Check if type is SkColor and add "--" to property name so that DevTools
+    // frontend will interpret this field as a color. Also convert SkColor value
+    // to rgba string.
+    if ((*member)->member_type() == "SkColor") {
+      SkColor color;
+      if (base::StringToUint(
+              base::UTF16ToUTF8((*member)->GetValueAsString(view_)), &color))
+        class_properties.emplace_back("--" + (*member)->member_name(),
+                                      color_utils::SkColorToRgbaString(color));
+    } else
+      class_properties.emplace_back(
+          (*member)->member_name(),
+          base::UTF16ToUTF8((*member)->GetValueAsString(view_)));
 
     if (member.IsLastMember()) {
       ret.emplace_back(member.GetCurrentCollectionName(), class_properties);
@@ -121,6 +151,7 @@
 }
 
 bool ViewElement::SetPropertiesFromString(const std::string& text) {
+  bool property_set = false;
   std::vector<std::string> tokens = base::SplitString(
       text, ":;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
@@ -128,8 +159,15 @@
     return false;
 
   for (size_t i = 0; i < tokens.size() - 1; i += 2) {
-    const std::string& property_name = tokens.at(i);
-    const std::string& property_value = base::ToLowerASCII(tokens.at(i + 1));
+    std::string property_name = tokens.at(i);
+    std::string property_value = base::ToLowerASCII(tokens.at(i + 1));
+
+    // Check if property is type SkColor.
+    if (GetSkColorPropertyName(property_name)) {
+      // Convert from CSS color format to SkColor.
+      if (!ParseColorFromFrontend(property_value, &property_value))
+        continue;
+    }
 
     views::metadata::ClassMetaData* metadata = view_->GetClassMetaData();
     views::metadata::MemberMetaDataBase* member =
@@ -150,9 +188,10 @@
     }
 
     member->SetValueAsString(view_, base::UTF8ToUTF16(property_value));
+    property_set = true;
   }
 
-  return true;
+  return property_set;
 }
 
 std::vector<std::string> ViewElement::GetAttributes() const {
diff --git a/components/ui_devtools/views/view_element_unittest.cc b/components/ui_devtools/views/view_element_unittest.cc
index 6e1d0bd..f327ed890 100644
--- a/components/ui_devtools/views/view_element_unittest.cc
+++ b/components/ui_devtools/views/view_element_unittest.cc
@@ -73,13 +73,18 @@
   int GetBoolProperty() const { return bool_property_; }
   void SetBoolProperty(bool bool_property) { bool_property_ = bool_property; }
 
+  SkColor GetColorProperty() const { return color_property_; }
+  void SetColorProperty(SkColor color) { color_property_ = color; }
+
  private:
   bool bool_property_ = false;
+  SkColor color_property_ = SK_ColorGRAY;
 };
 
 BEGIN_METADATA(NamedTestView)
 METADATA_PARENT_CLASS(views::View)
 ADD_PROPERTY_METADATA(NamedTestView, bool, BoolProperty)
+ADD_PROPERTY_METADATA(NamedTestView, SkColor, ColorProperty)
 END_METADATA()
 
 class ViewElementTest : public views::ViewsTestBase {
@@ -247,6 +252,38 @@
   view()->parent()->RemoveChildView(view());
 }
 
+TEST_F(ViewElementTest, ColorProperty) {
+  EXPECT_EQ(GetPropertyIndices(element(), "--ColorProperty").first, 0U);
+  DCHECK_EQ(view()->GetColorProperty(), SK_ColorGRAY);
+
+  EXPECT_TRUE(element()->SetPropertiesFromString(
+      "--ColorProperty: rgba(0,0,  255, 1);"));
+  EXPECT_EQ(view()->GetColorProperty(), SK_ColorBLUE);
+
+  EXPECT_TRUE(element()->SetPropertiesFromString("--ColorProperty: #0352fc"));
+  EXPECT_EQ(view()->GetColorProperty(), SkColorSetARGB(255, 3, 82, 252));
+
+  EXPECT_TRUE(element()->SetPropertiesFromString(
+      "--ColorProperty: hsl(240, 84%, 28%);"));
+  EXPECT_EQ(view()->GetColorProperty(), SkColorSetARGB(255, 11, 11, 131));
+}
+
+TEST_F(ViewElementTest, BadColorProperty) {
+  DCHECK_EQ(view()->GetColorProperty(), SK_ColorGRAY);
+
+  EXPECT_FALSE(
+      element()->SetPropertiesFromString("-ColorProperty: rgba(1,2,3,4);"));
+  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
+
+  EXPECT_FALSE(
+      element()->SetPropertiesFromString("--ColorProperty: rgba(1,2,3,4;"));
+  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
+
+  EXPECT_FALSE(
+      element()->SetPropertiesFromString("--ColorProperty: rgb(1,2,3,4;)"));
+  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
+}
+
 TEST_F(ViewElementTest, GetSources) {
   std::vector<UIElement::Source> sources = element()->GetSources();
 
diff --git a/components/viz/common/gpu/context_cache_controller_unittest.cc b/components/viz/common/gpu/context_cache_controller_unittest.cc
index a2bd148..c380ea6 100644
--- a/components/viz/common/gpu/context_cache_controller_unittest.cc
+++ b/components/viz/common/gpu/context_cache_controller_unittest.cc
@@ -176,7 +176,7 @@
     std::vector<uint8_t> image_data(image_info.computeMinByteSize());
     SkPixmap pixmap(image_info, image_data.data(), image_info.minRowBytes());
     auto image = SkImage::MakeRasterCopy(pixmap);
-    auto image_gpu = image->makeTextureImage(gr_context, nullptr);
+    auto image_gpu = image->makeTextureImage(gr_context);
     gr_context->flush();
   }
 
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index b286ebfe..e2f3b6f 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -3409,12 +3409,9 @@
     EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
     UpdateBeginFrameTime(support_.get(), frame_time);
     submit_frame();
-    // If we've submitted more than one frame without drawing, there will
-    // always be presentation feedback so ShouldSendBeginFrame should always
-    // return true.
-    if (i > 0)
-      EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
-
+    // Immediately after submitting frame, because there is presentation
+    // feedback queued up, ShouldSendBeginFrame should always return true.
+    EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
     // Clear the presentation feedbacks.
     UpdateBeginFrameTime(support_.get(), frame_time);
   }
@@ -3567,11 +3564,9 @@
     UpdateBeginFrameTime(sub_support.get(), frame_time);
     sub_support->SubmitCompositorFrame(sub_local_surface_id,
                                        MakeDefaultCompositorFrame());
-    // If we've submitted more than one frame without drawing, there will
-    // always be presentation feedback so ShouldSendBeginFrame should always
-    // return true.
-    if (i > 0)
-      EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+    // Immediately after submitting frame, because there is presentation
+    // feedback queued up, ShouldSendBeginFrame should always return true.
+    EXPECT_TRUE(ShouldSendBeginFrame(sub_support.get(), frame_time));
     // Clear the presentation feedbacks.
     UpdateBeginFrameTime(sub_support.get(), frame_time);
   }
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index b6d0075..a4f0b5b 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -14,7 +14,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/frame_timing_details_map.h"
 #include "components/viz/common/quads/compositor_frame.h"
@@ -68,13 +67,7 @@
   // exceeded, we throttle sBeginFrames to 1 per second. Limit must be at least
   // 1, as the relative ordering of renderer / browser frame submissions allows
   // us to have one outstanding undrawn frame under normal operation.
-#if defined(OS_ANDROID)
-  // TODO(ericrk): Revert this. Setting to 0 temporarily to test the impact of
-  // this change on a latency regression. See https://crbug.com/959048
-  static constexpr uint32_t kUndrawnFrameLimit = 0;
-#else
   static constexpr uint32_t kUndrawnFrameLimit = 3;
-#endif
 
   CompositorFrameSinkSupport(mojom::CompositorFrameSinkClient* client,
                              FrameSinkManagerImpl* frame_sink_manager,
diff --git a/content/app/android/content_child_process_service_delegate.cc b/content/app/android/content_child_process_service_delegate.cc
index f9fb954..70724fc 100644
--- a/content/app/android/content_child_process_service_delegate.cc
+++ b/content/app/android/content_child_process_service_delegate.cc
@@ -49,14 +49,14 @@
   // Overriden from ScopedSurfaceRequestConduit:
   void ForwardSurfaceOwnerForSurfaceRequest(
       const base::UnguessableToken& request_token,
-      const gpu::SurfaceOwner* surface_owner) override {
+      const gpu::TextureOwner* texture_owner) override {
     JNIEnv* env = base::android::AttachCurrentThread();
 
     content::
         Java_ContentChildProcessServiceDelegate_forwardSurfaceForSurfaceRequest(
             env, service_impl_,
             base::android::UnguessableTokenAndroid::Create(env, request_token),
-            surface_owner->CreateJavaSurface().j_surface());
+            texture_owner->CreateJavaSurface().j_surface());
   }
 
   // Overridden from GpuSurfaceLookup:
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d1ad328e..24cd1b19 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2415,6 +2415,7 @@
       "//build/config/freetype",
       "//content/public/android:jni",
       "//device/gamepad/public/mojom",
+      "//gpu/ipc/common:android_texture_owner",
       "//media",
       "//media/capture/content/android",
       "//media/capture/video/android",
diff --git a/content/browser/android/scoped_surface_request_manager.cc b/content/browser/android/scoped_surface_request_manager.cc
index 56575514..befd0a7 100644
--- a/content/browser/android/scoped_surface_request_manager.cc
+++ b/content/browser/android/scoped_surface_request_manager.cc
@@ -57,9 +57,9 @@
 
 void ScopedSurfaceRequestManager::ForwardSurfaceOwnerForSurfaceRequest(
     const base::UnguessableToken& request_token,
-    const gpu::SurfaceOwner* surface_owner) {
+    const gpu::TextureOwner* texture_owner) {
   FulfillScopedSurfaceRequest(request_token,
-                              surface_owner->CreateJavaSurface());
+                              texture_owner->CreateJavaSurface());
 }
 
 void ScopedSurfaceRequestManager::FulfillScopedSurfaceRequest(
diff --git a/content/browser/android/scoped_surface_request_manager.h b/content/browser/android/scoped_surface_request_manager.h
index 2030ec8..f426b65 100644
--- a/content/browser/android/scoped_surface_request_manager.h
+++ b/content/browser/android/scoped_surface_request_manager.h
@@ -51,7 +51,7 @@
   // Can be called from any thread.
   void ForwardSurfaceOwnerForSurfaceRequest(
       const base::UnguessableToken& request_token,
-      const gpu::SurfaceOwner* surface_owner) override;
+      const gpu::TextureOwner* texture_owner) override;
 
   void clear_requests_for_testing() { request_callbacks_.clear(); }
 
diff --git a/content/browser/android/scoped_surface_request_manager_unittest.cc b/content/browser/android/scoped_surface_request_manager_unittest.cc
index bdff6917..a934b07 100644
--- a/content/browser/android/scoped_surface_request_manager_unittest.cc
+++ b/content/browser/android/scoped_surface_request_manager_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/callback_forward.h"
 #include "base/run_loop.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "gpu/ipc/common/android/surface_owner_android.h"
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/android/scoped_java_surface.h"
 #include "ui/gl/android/surface_texture.h"
@@ -27,7 +27,8 @@
     last_received_request_ = 0;
     dummy_token_ = base::UnguessableToken::Deserialize(123, 456);
 
-    surface_owner = gpu::SurfaceOwner::Create(0);
+    mock_texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
+        0, nullptr, nullptr);
     dummy_request_ =
         base::Bind(&ScopedSurfaceRequestManagerUnitTest::DummyCallback,
                    base::Unretained(this));
@@ -47,7 +48,7 @@
 
   ScopedSurfaceRequestManager::ScopedSurfaceRequestCB dummy_request_;
   ScopedSurfaceRequestManager::ScopedSurfaceRequestCB specific_logging_request_;
-  std::unique_ptr<gpu::SurfaceOwner> surface_owner;
+  scoped_refptr<NiceMock<gpu::MockTextureOwner>> mock_texture_owner;
 
   int last_received_request_;
   const int kSpecificCallbackId = 1357;
@@ -140,8 +141,8 @@
        FulfillUnregisteredRequest_ShouldDoNothing) {
   manager_->RegisterScopedSurfaceRequest(specific_logging_request_);
 
-  manager_->FulfillScopedSurfaceRequest(dummy_token_,
-                                        surface_owner->CreateJavaSurface());
+  manager_->FulfillScopedSurfaceRequest(
+      dummy_token_, mock_texture_owner->CreateJavaSurface());
 
   EXPECT_EQ(1, manager_->request_count_for_testing());
   EXPECT_NE(kSpecificCallbackId, last_received_request_);
@@ -159,8 +160,8 @@
       base::Bind(&ScopedSurfaceRequestManagerUnitTest::LoggingCallback,
                  base::Unretained(this), kOtherCallbackId));
 
-  manager_->FulfillScopedSurfaceRequest(specific_token,
-                                        surface_owner->CreateJavaSurface());
+  manager_->FulfillScopedSurfaceRequest(
+      specific_token, mock_texture_owner->CreateJavaSurface());
 
   base::RunLoop().RunUntilIdle();
 
@@ -175,7 +176,8 @@
   base::UnguessableToken token =
       manager_->RegisterScopedSurfaceRequest(specific_logging_request_);
 
-  manager_->ForwardSurfaceOwnerForSurfaceRequest(token, surface_owner.get());
+  manager_->ForwardSurfaceOwnerForSurfaceRequest(token,
+                                                 mock_texture_owner.get());
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 8d58aed..d7d97144 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -30,6 +30,7 @@
     service_manager::BinderMapWithContext<RenderFrameHost*>* map) {
   map->Add<blink::mojom::BackgroundFetchService>(
       base::BindRepeating(&BackgroundFetchServiceImpl::CreateForFrame));
+  GetContentClient()->browser()->RegisterBrowserInterfaceBindersForFrame(map);
 }
 
 void PopulateBinderMap(RenderFrameHostImpl* host,
@@ -65,7 +66,7 @@
 
 // Shared workers
 url::Origin GetContextForHost(SharedWorkerHost* host) {
-  return url::Origin::Create(host->instance()->url());
+  return url::Origin::Create(host->instance().url());
 }
 
 void PopulateSharedWorkerBinders(SharedWorkerHost* host,
diff --git a/content/browser/browser_interface_broker_impl.h b/content/browser/browser_interface_broker_impl.h
index 664c600c..10be84f 100644
--- a/content/browser/browser_interface_broker_impl.h
+++ b/content/browser/browser_interface_broker_impl.h
@@ -21,7 +21,7 @@
  public:
   BrowserInterfaceBrokerImpl(ExecutionContextHost* host) : host_(host) {
     internal::PopulateBinderMap(host, &binder_map_);
-    internal::PopulateBinderMapWithContext(host, &binder_map_with_context);
+    internal::PopulateBinderMapWithContext(host, &binder_map_with_context_);
   }
 
   // blink::mojom::BrowserInterfaceBroker
@@ -30,8 +30,8 @@
     auto interface_name = receiver.interface_name().value();
     auto pipe = receiver.PassPipe();
     if (!binder_map_.TryBind(interface_name, &pipe)) {
-      binder_map_with_context.TryBind(internal::GetContextForHost(host_),
-                                      interface_name, &pipe);
+      binder_map_with_context_.TryBind(internal::GetContextForHost(host_),
+                                       interface_name, &pipe);
     }
   }
 
@@ -39,7 +39,7 @@
   ExecutionContextHost* const host_;
   service_manager::BinderMap binder_map_;
   service_manager::BinderMapWithContext<InterfaceBinderContext>
-      binder_map_with_context;
+      binder_map_with_context_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserInterfaceBrokerImpl);
 };
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.cc b/content/browser/devtools/shared_worker_devtools_agent_host.cc
index 1452e48e..a47463c 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/devtools/shared_worker_devtools_agent_host.h"
 
+#include <memory>
+#include <utility>
+
 #include "content/browser/devtools/devtools_renderer_channel.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/protocol/inspector_handler.h"
@@ -13,7 +16,6 @@
 #include "content/browser/devtools/protocol/target_handler.h"
 #include "content/browser/devtools/shared_worker_devtools_manager.h"
 #include "content/browser/worker_host/shared_worker_host.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/browser/worker_host/shared_worker_service_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -28,7 +30,7 @@
       state_(WORKER_NOT_READY),
       worker_host_(worker_host),
       devtools_worker_token_(devtools_worker_token),
-      instance_(new SharedWorkerInstance(*worker_host->instance())) {
+      instance_(worker_host->instance()) {
   NotifyCreated();
 }
 
@@ -49,11 +51,11 @@
 }
 
 std::string SharedWorkerDevToolsAgentHost::GetTitle() {
-  return instance_->name();
+  return instance_.name();
 }
 
 GURL SharedWorkerDevToolsAgentHost::GetURL() {
-  return instance_->url();
+  return instance_.url();
 }
 
 bool SharedWorkerDevToolsAgentHost::Activate() {
@@ -86,7 +88,7 @@
 }
 
 bool SharedWorkerDevToolsAgentHost::Matches(SharedWorkerHost* worker_host) {
-  return instance_->Matches(*worker_host->instance());
+  return instance_.Matches(worker_host->instance());
 }
 
 void SharedWorkerDevToolsAgentHost::WorkerReadyForInspection(
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.h b/content/browser/devtools/shared_worker_devtools_agent_host.h
index d173f12a..41b264e 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.h
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.h
@@ -5,13 +5,16 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_AGENT_HOST_H_
 #define CONTENT_BROWSER_DEVTOOLS_SHARED_WORKER_DEVTOOLS_AGENT_HOST_H_
 
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "base/unguessable_token.h"
 #include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/browser/worker_host/shared_worker_instance.h"
 
 namespace content {
 
-class SharedWorkerInstance;
 class SharedWorkerHost;
 
 class SharedWorkerDevToolsAgentHost : public DevToolsAgentHostImpl {
@@ -58,7 +61,7 @@
   WorkerState state_;
   SharedWorkerHost* worker_host_;
   base::UnguessableToken devtools_worker_token_;
-  std::unique_ptr<SharedWorkerInstance> instance_;
+  SharedWorkerInstance instance_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedWorkerDevToolsAgentHost);
 };
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 1555d40..ee37f2d 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -1847,56 +1847,6 @@
             downloads[0]->GetLastReason());
 }
 
-// Test that content length mismatch errors are handled properly.
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ContentLengthMismatch) {
-  GURL url = TestDownloadHttpResponse::GetNextURLForDownload();
-  GURL server_url = embedded_test_server()->GetURL(url.host(), url.path());
-  // Server response doesn't contain strong validators.
-  TestDownloadHttpResponse::StartServingStaticResponse(
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 100000\r\n"
-      "\r\n"
-      "abc\r\n",
-      server_url);
-
-  auto download_parameters = std::make_unique<download::DownloadUrlParameters>(
-      server_url, TRAFFIC_ANNOTATION_FOR_TESTS);
-  DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters));
-  std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
-  observer->WaitForFinished();
-
-  // Verify download completed without any interruptions.
-  std::vector<download::DownloadItem*> downloads;
-  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
-  EXPECT_EQ(download::DownloadItem::COMPLETE, downloads[0]->GetState());
-  EXPECT_EQ(download::DOWNLOAD_INTERRUPT_REASON_NONE,
-            downloads[0]->GetLastReason());
-  EXPECT_EQ(0, downloads[0]->GetAutoResumeCount());
-  downloads[0]->Remove();
-
-  // Change server response to include strong validators.
-  TestDownloadHttpResponse::StartServingStaticResponse(
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 100000\r\n"
-      "Etag: xyz\r\n"
-      "\r\n"
-      "abc\r\n",
-      server_url);
-  download_parameters = std::make_unique<download::DownloadUrlParameters>(
-      server_url, TRAFFIC_ANNOTATION_FOR_TESTS);
-  DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters));
-  std::unique_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
-  observer2->WaitForFinished();
-
-  // Verify the new download completed with 1 auto resumption attempt.
-  downloads.clear();
-  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-  EXPECT_EQ(1u, downloads.size());
-  EXPECT_EQ(download::DownloadItem::COMPLETE, downloads[0]->GetState());
-  EXPECT_EQ(1, downloads[0]->GetAutoResumeCount());
-}
-
 // If the server response for the resumption request specifies a bad range (i.e.
 // not the range that was requested), then the download should be marked as
 // interrupted and restart from the beginning.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 702a34e..613d425 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5040,17 +5040,8 @@
     std::string scheme = common_params->url.scheme();
     const auto& webui_schemes = URLDataManagerBackend::GetWebUISchemes();
     if (base::Contains(webui_schemes, scheme)) {
-      mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_for_webui;
-      auto factory_receiver =
-          factory_for_webui.InitWithNewPipeAndPassReceiver();
-      GetContentClient()->browser()->WillCreateURLLoaderFactory(
-          browser_context, this, GetProcess()->GetID(),
-          false /* is_navigation */, false /* is_download */,
-          GetOriginForURLLoaderFactory(navigation_request)
-              .value_or(url::Origin()),
-          &factory_receiver, nullptr /* header_client */,
-          nullptr /* bypass_redirect_checks */);
-      CreateWebUIURLLoaderBinding(this, scheme, std::move(factory_receiver));
+      network::mojom::URLLoaderFactoryPtr factory_for_webui =
+          CreateWebUIURLLoaderBinding(this, scheme);
       // If the renderer has webui bindings, then don't give it access to
       // network loader for security reasons.
       // http://crbug.com/829412: make an exception for a small whitelist
@@ -5058,7 +5049,7 @@
       if ((enabled_bindings_ & kWebUIBindingsPolicyMask) &&
           !GetContentClient()->browser()->IsWebUIAllowedToMakeNetworkRequests(
               url::Origin::Create(common_params->url.GetOrigin()))) {
-        pending_default_factory = std::move(factory_for_webui);
+        pending_default_factory = factory_for_webui.PassInterface();
         // WebUIURLLoaderFactory will kill the renderer if it sees a request
         // with a non-chrome scheme. Register a URLLoaderFactory for the about
         // scheme so about:blank doesn't kill the renderer.
@@ -5068,7 +5059,7 @@
         // This is a webui scheme that doesn't have webui bindings. Give it
         // access to the network loader as it might require it.
         subresource_loader_factories->pending_scheme_specific_factories()
-            .emplace(scheme, std::move(factory_for_webui));
+            .emplace(scheme, factory_for_webui.PassInterface());
       }
     }
 
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 6bf23340..5174402 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1242,19 +1242,13 @@
   // Check if a web UI scheme wants to handle this request.
   FrameTreeNode* frame_tree_node =
       FrameTreeNode::GloballyFindByID(frame_tree_node_id);
+  network::mojom::URLLoaderFactoryPtrInfo factory_for_webui;
   const auto& schemes = URLDataManagerBackend::GetWebUISchemes();
   std::string scheme = new_request->url.scheme();
-  mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_for_webui;
   if (base::Contains(schemes, scheme)) {
-    auto factory_receiver = factory_for_webui.InitWithNewPipeAndPassReceiver();
-    GetContentClient()->browser()->WillCreateURLLoaderFactory(
-        partition->browser_context(), frame_tree_node->current_frame_host(),
-        frame_tree_node->current_frame_host()->GetProcess()->GetID(),
-        true /* is_navigation */, false /* is_download */, url::Origin(),
-        &factory_receiver, nullptr /* header_client */,
-        nullptr /* bypass_redirect_checks */);
-    CreateWebUIURLLoaderBinding(frame_tree_node->current_frame_host(), scheme,
-                                std::move(factory_receiver));
+    factory_for_webui = CreateWebUIURLLoaderBinding(
+                            frame_tree_node->current_frame_host(), scheme)
+                            .PassInterface();
   }
 
   network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
diff --git a/content/browser/media/session/audio_focus_delegate_default.cc b/content/browser/media/session/audio_focus_delegate_default.cc
index 736f43c..3570c8fc 100644
--- a/content/browser/media/session/audio_focus_delegate_default.cc
+++ b/content/browser/media/session/audio_focus_delegate_default.cc
@@ -182,7 +182,10 @@
   GetSystemConnector()->BindInterface(media_session::mojom::kServiceName,
                                       mojo::MakeRequest(&audio_focus_ptr_));
 
-  audio_focus_ptr_->SetSourceName(kAudioFocusSourceName);
+  // We associate all media sessions with the browser context so we can filter
+  // by browser context in the UI.
+  audio_focus_ptr_->SetSource(media_session_->GetSourceId(),
+                              kAudioFocusSourceName);
 }
 
 // static
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 31517da..4cd4b5e 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -21,6 +21,7 @@
 #include "content/browser/media/session/media_session_service_impl.h"
 #include "content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/media_session.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
@@ -57,6 +58,33 @@
 using MediaSessionSuspendedSource =
     MediaSessionUmaHelper::MediaSessionSuspendedSource;
 
+const char kMediaSessionDataName[] = "MediaSessionDataName";
+
+class MediaSessionData : public base::SupportsUserData::Data {
+ public:
+  MediaSessionData() = default;
+
+  static MediaSessionData* GetOrCreate(BrowserContext* context) {
+    auto* data = static_cast<MediaSessionData*>(
+        context->GetUserData(kMediaSessionDataName));
+
+    if (!data) {
+      auto new_data = std::make_unique<MediaSessionData>();
+      data = new_data.get();
+      context->SetUserData(kMediaSessionDataName, std::move(new_data));
+    }
+
+    return data;
+  }
+
+  const base::UnguessableToken& source_id() const { return source_id_; }
+
+ private:
+  base::UnguessableToken source_id_ = base::UnguessableToken::Create();
+
+  DISALLOW_COPY_AND_ASSIGN(MediaSessionData);
+};
+
 size_t ComputeFrameDepth(RenderFrameHost* rfh,
                          MapRenderFrameHostToDepth* map_rfh_to_depth) {
   DCHECK(rfh);
@@ -1219,6 +1247,11 @@
   return routed_service_ && base::Contains(routed_service_->actions(), action);
 }
 
+const base::UnguessableToken& MediaSessionImpl::GetSourceId() const {
+  return MediaSessionData::GetOrCreate(web_contents()->GetBrowserContext())
+      ->source_id();
+}
+
 void MediaSessionImpl::RebuildAndNotifyActionsChanged() {
   std::set<media_session::mojom::MediaSessionAction> actions =
       routed_service_ ? routed_service_->actions()
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index c9f3c94..cf1bf7a2 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -264,6 +264,10 @@
   // Returns whether the action should be routed to |routed_service_|.
   bool ShouldRouteAction(media_session::mojom::MediaSessionAction action) const;
 
+  // Returns the source ID which links media sessions on the same browser
+  // context together.
+  CONTENT_EXPORT const base::UnguessableToken& GetSourceId() const;
+
  private:
   friend class content::WebContentsUserData<MediaSessionImpl>;
   friend class ::MediaSessionImplBrowserTest;
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc
index e49d211..2482228 100644
--- a/content/browser/media/session/media_session_impl_unittest.cc
+++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -12,9 +12,11 @@
 #include "content/browser/media/session/media_session_player_observer.h"
 #include "content/browser/media/session/mock_media_session_player_observer.h"
 #include "content/browser/media/session/mock_media_session_service_impl.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/system_connector.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_service_manager_context.h"
+#include "content/test/test_web_contents.h"
 #include "media/base/media_content_type.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
@@ -645,4 +647,19 @@
 
 #endif  // !defined(OS_ANDROID)
 
+TEST_F(MediaSessionImplTest, SourceId_SameBrowserContext) {
+  auto other_contents = TestWebContents::Create(browser_context(), nullptr);
+  MediaSessionImpl* other_session = MediaSessionImpl::Get(other_contents.get());
+
+  EXPECT_EQ(GetMediaSession()->GetSourceId(), other_session->GetSourceId());
+}
+
+TEST_F(MediaSessionImplTest, SourceId_DifferentBrowserContext) {
+  auto other_context = CreateBrowserContext();
+  auto other_contents = TestWebContents::Create(other_context.get(), nullptr);
+  MediaSessionImpl* other_session = MediaSessionImpl::Get(other_contents.get());
+
+  EXPECT_NE(GetMediaSession()->GetSourceId(), other_session->GetSourceId());
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc
index 1cdeba1..e992e45 100644
--- a/content/browser/renderer_host/render_widget_targeter.cc
+++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -5,6 +5,8 @@
 #include "content/browser/renderer_host/render_widget_targeter.h"
 
 #include "base/bind.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
@@ -12,8 +14,11 @@
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/renderer_host/input/one_shot_timeout_monitor.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/scoped_active_url.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "ui/events/blink/blink_event_util.h"
@@ -40,6 +45,33 @@
 
 constexpr const char kTracingCategory[] = "input,latency";
 
+// This function helps with debugging the reasons of viz hit testing mismatch.
+void DumpWithoutCrashing(RenderWidgetHostViewBase* root_view,
+                         RenderWidgetHostViewBase* target,
+                         const base::Optional<gfx::PointF>& target_location) {
+  RenderViewHostImpl* rvh =
+      RenderViewHostImpl::From(root_view->GetRenderWidgetHost());
+  if (!rvh || !rvh->GetMainFrame())
+    return;
+  ScopedActiveURL scoped_active_url(rvh);
+
+  static auto* crash_key = base::debug::AllocateCrashKeyString(
+      "vizhittest-mismatch-v2-coordinate", base::debug::CrashKeySize::Size32);
+  const std::string global_coordinate =
+      target->TransformPointToRootCoordSpaceF(target_location.value())
+          .ToString();
+  base::debug::SetCrashKeyString(crash_key, global_coordinate);
+
+  crash_key = base::debug::AllocateCrashKeyString(
+      "vizhittest-mismatch-v2-viewport-size",
+      base::debug::CrashKeySize::Size32);
+  const std::string viewport_size =
+      root_view->GetVisibleViewportSize().ToString();
+  base::debug::SetCrashKeyString(crash_key, viewport_size);
+
+  base::debug::DumpWithoutCrashing();
+}
+
 }  // namespace
 
 class TracingUmaTracker {
@@ -483,6 +515,8 @@
     static const char* kResultsMatchHistogramName =
         "Event.VizHitTestSurfaceLayer.ResultsMatch";
     HitTestResultsMatch bucket = GetHitTestResultsMatchBucket(target, request);
+    if (bucket == HitTestResultsMatch::kDoNotMatch)
+      DumpWithoutCrashing(request->GetRootView(), target, target_location);
     UMA_HISTOGRAM_ENUMERATION(kResultsMatchHistogramName, bucket,
                               HitTestResultsMatch::kMaxValue);
     FlushEventQueue(true);
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index fa279243..58787a5 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -218,9 +218,10 @@
 
   ~WebUIURLLoaderFactory() override {}
 
-  void AddBinding(mojo::PendingReceiver<network::mojom::URLLoaderFactory>
-                      factory_receiver) {
-    loader_factory_bindings_.AddBinding(this, std::move(factory_receiver));
+  network::mojom::URLLoaderFactoryPtr CreateBinding() {
+    network::mojom::URLLoaderFactoryPtr factory;
+    loader_factory_bindings_.AddBinding(this, mojo::MakeRequest(&factory));
+    return factory;
   }
 
   // network::mojom::URLLoaderFactory implementation:
@@ -324,10 +325,9 @@
                                                  std::move(allowed_hosts));
 }
 
-void CreateWebUIURLLoaderBinding(
+network::mojom::URLLoaderFactoryPtr CreateWebUIURLLoaderBinding(
     RenderFrameHost* render_frame_host,
-    const std::string& scheme,
-    mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver) {
+    const std::string& scheme) {
   GlobalFrameRoutingId routing_id(render_frame_host->GetRoutingID(),
                                   render_frame_host->GetProcess()->GetID());
   if (g_web_ui_url_loader_factories.Get().find(routing_id) ==
@@ -337,8 +337,7 @@
         std::make_unique<WebUIURLLoaderFactory>(render_frame_host, scheme,
                                                 base::flat_set<std::string>());
   }
-  g_web_ui_url_loader_factories.Get()[routing_id]->AddBinding(
-      std::move(factory_receiver));
+  return g_web_ui_url_loader_factories.Get()[routing_id]->CreateBinding();
 }
 
 }  // namespace content
diff --git a/content/browser/webui/web_ui_url_loader_factory_internal.h b/content/browser/webui/web_ui_url_loader_factory_internal.h
index 3251a1af..be4749dd 100644
--- a/content/browser/webui/web_ui_url_loader_factory_internal.h
+++ b/content/browser/webui/web_ui_url_loader_factory_internal.h
@@ -14,10 +14,9 @@
 // the given |render_frame_host|. The factory will only create loaders for
 // requests with the same scheme as |scheme|. This is needed because there is
 // more than one scheme used for WebUI, and not all have WebUI bindings.
-void CreateWebUIURLLoaderBinding(
+network::mojom::URLLoaderFactoryPtr CreateWebUIURLLoaderBinding(
     RenderFrameHost* render_frame_host,
-    const std::string& scheme,
-    mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver);
+    const std::string& scheme);
 
 }  // namespace content
 
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 4c17dfc..0f8bd05 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -19,7 +19,6 @@
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/worker_host/shared_worker_content_settings_proxy_impl.h"
-#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/browser/worker_host/shared_worker_service_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -76,17 +75,15 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedDevToolsHandle);
 };
 
-SharedWorkerHost::SharedWorkerHost(
-    SharedWorkerServiceImpl* service,
-    std::unique_ptr<SharedWorkerInstance> instance,
-    int worker_process_id)
+SharedWorkerHost::SharedWorkerHost(SharedWorkerServiceImpl* service,
+                                   const SharedWorkerInstance& instance,
+                                   int worker_process_id)
     : binding_(this),
       service_(service),
-      instance_(std::move(instance)),
+      instance_(instance),
       worker_process_id_(worker_process_id),
       next_connection_request_id_(1),
       interface_provider_binding_(this) {
-  DCHECK(instance_);
   // Set up the worker interface request. This is needed first in either
   // AddClient() or Start(). AddClient() can sometimes be called before Start()
   // when two clients call new SharedWorker() at around the same time.
@@ -148,9 +145,9 @@
   AdvanceTo(Phase::kStarted);
 
   blink::mojom::SharedWorkerInfoPtr info(blink::mojom::SharedWorkerInfo::New(
-      instance_->url(), instance_->name(), instance_->content_security_policy(),
-      instance_->content_security_policy_type(),
-      instance_->creation_address_space()));
+      instance_.url(), instance_.name(), instance_.content_security_policy(),
+      instance_.content_security_policy_type(),
+      instance_.creation_address_space()));
 
   // Register with DevTools.
   bool pause_on_start;
@@ -174,7 +171,7 @@
   // Set up content settings interface.
   blink::mojom::WorkerContentSettingsProxyPtr content_settings;
   content_settings_ = std::make_unique<SharedWorkerContentSettingsProxyImpl>(
-      instance_->url(), this, mojo::MakeRequest(&content_settings));
+      instance_.url(), this, mojo::MakeRequest(&content_settings));
 
   // Set up host interface.
   blink::mojom::SharedWorkerHostPtr host;
@@ -255,7 +252,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   auto* worker_process_host = RenderProcessHost::FromID(worker_process_id_);
-  url::Origin origin = instance_->constructor_origin();
+  url::Origin origin = instance_.constructor_origin();
   network::mojom::TrustedURLLoaderHeaderClientPtrInfo no_header_client;
 
   // TODO(yhirano): Support COEP.
@@ -366,8 +363,6 @@
 SharedWorkerHost::ClientInfo::~ClientInfo() {}
 
 void SharedWorkerHost::OnConnected(int connection_request_id) {
-  if (!instance_)
-    return;
   for (const ClientInfo& info : clients_) {
     if (info.connection_request_id != connection_request_id)
       continue;
@@ -461,7 +456,7 @@
                                  const blink::MessagePortChannel& port) {
   // Pass the actual creation context type, so the client can understand if
   // there is a mismatch between security levels.
-  client->OnCreated(instance_->creation_context_type());
+  client->OnCreated(instance_.creation_context_type());
 
   clients_.emplace_back(std::move(client), next_connection_request_id_++,
                         client_process_id, frame_id);
@@ -516,7 +511,7 @@
 
   BindWorkerInterface(interface_name, std::move(interface_pipe),
                       worker_process_host,
-                      url::Origin::Create(instance()->url()));
+                      url::Origin::Create(instance_.url()));
 }
 
 }  // namespace content
diff --git a/content/browser/worker_host/shared_worker_host.h b/content/browser/worker_host/shared_worker_host.h
index 3e20258..279f06b 100644
--- a/content/browser/worker_host/shared_worker_host.h
+++ b/content/browser/worker_host/shared_worker_host.h
@@ -8,7 +8,7 @@
 #include <list>
 #include <memory>
 #include <set>
-#include <utility>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -16,6 +16,7 @@
 #include "base/strings/string16.h"
 #include "base/unguessable_token.h"
 #include "content/browser/browser_interface_broker_impl.h"
+#include "content/browser/worker_host/shared_worker_instance.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/render_process_host.h"
@@ -43,7 +44,6 @@
 class ServiceWorkerNavigationHandle;
 class ServiceWorkerObjectHost;
 class SharedWorkerContentSettingsProxyImpl;
-class SharedWorkerInstance;
 class SharedWorkerServiceImpl;
 
 // The SharedWorkerHost is the interface that represents the browser side of
@@ -55,7 +55,7 @@
       public service_manager::mojom::InterfaceProvider {
  public:
   SharedWorkerHost(SharedWorkerServiceImpl* service,
-                   std::unique_ptr<SharedWorkerInstance> instance,
+                   const SharedWorkerInstance& instance,
                    int worker_process_id);
   ~SharedWorkerHost() override;
 
@@ -116,7 +116,7 @@
   void SetServiceWorkerHandle(
       std::unique_ptr<ServiceWorkerNavigationHandle> service_worker_handle);
 
-  SharedWorkerInstance* instance() { return instance_.get(); }
+  const SharedWorkerInstance& instance() const { return instance_; }
   int worker_process_id() const { return worker_process_id_; }
   bool IsAvailable() const;
 
@@ -179,7 +179,7 @@
 
   // |service_| owns |this|.
   SharedWorkerServiceImpl* service_;
-  std::unique_ptr<SharedWorkerInstance> instance_;
+  SharedWorkerInstance instance_;
   ClientList clients_;
 
   blink::mojom::SharedWorkerRequest worker_request_;
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 0690feb..8614d264 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -64,12 +65,12 @@
     blink::mojom::SharedWorkerCreationContextType creation_context_type =
         blink::mojom::SharedWorkerCreationContextType::kSecure;
 
-    auto instance = std::make_unique<SharedWorkerInstance>(
-        url, name, origin, content_security_policy,
-        content_security_policy_type, creation_address_space,
-        creation_context_type);
+    SharedWorkerInstance instance(url, name, origin, content_security_policy,
+                                  content_security_policy_type,
+                                  creation_address_space,
+                                  creation_context_type);
     auto host = std::make_unique<SharedWorkerHost>(
-        &service_, std::move(instance), mock_render_process_host_.GetID());
+        &service_, instance, mock_render_process_host_.GetID());
     auto weak_host = host->AsWeakPtr();
     service_.worker_hosts_.insert(std::move(host));
     return weak_host;
@@ -157,8 +158,8 @@
   blink::mojom::SharedWorkerHostPtr worker_host;
   blink::mojom::SharedWorkerRequest worker_request;
   EXPECT_TRUE(factory_impl.CheckReceivedCreateSharedWorker(
-      host->instance()->url(), host->instance()->name(),
-      host->instance()->content_security_policy_type(), &worker_host,
+      host->instance().url(), host->instance().name(),
+      host->instance().content_security_policy_type(), &worker_host,
       &worker_request));
   {
     MockSharedWorker worker(std::move(worker_request));
@@ -265,8 +266,8 @@
     blink::mojom::SharedWorkerHostPtr worker_host;
     blink::mojom::SharedWorkerRequest worker_request;
     EXPECT_TRUE(factory_impl.CheckReceivedCreateSharedWorker(
-        host->instance()->url(), host->instance()->name(),
-        host->instance()->content_security_policy_type(), &worker_host,
+        host->instance().url(), host->instance().name(),
+        host->instance().content_security_policy_type(), &worker_host,
         &worker_request));
     MockSharedWorker worker(std::move(worker_request));
 
@@ -307,8 +308,8 @@
     blink::mojom::SharedWorkerHostPtr worker_host;
     blink::mojom::SharedWorkerRequest worker_request;
     EXPECT_TRUE(factory_impl.CheckReceivedCreateSharedWorker(
-        host->instance()->url(), host->instance()->name(),
-        host->instance()->content_security_policy_type(), &worker_host,
+        host->instance().url(), host->instance().name(),
+        host->instance().content_security_policy_type(), &worker_host,
         &worker_request));
     MockSharedWorker worker(std::move(worker_request));
 
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index 17224009..b7228d6 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -70,7 +70,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   for (auto& host : worker_hosts_) {
     if (host->IsAvailable() &&
-        host->instance()->Matches(url, name, constructor_origin)) {
+        host->instance().Matches(url, name, constructor_origin)) {
       host->TerminateWorker();
       return true;
     }
@@ -140,16 +140,16 @@
     return;
   }
 
-  auto instance = std::make_unique<SharedWorkerInstance>(
+  SharedWorkerInstance instance(
       info->url, info->name, render_frame_host->GetLastCommittedOrigin(),
       info->content_security_policy, info->content_security_policy_type,
       info->creation_address_space, creation_context_type);
 
-  SharedWorkerHost* host = FindAvailableSharedWorkerHost(*instance);
+  SharedWorkerHost* host = FindAvailableSharedWorkerHost(instance);
   if (host) {
     // Non-secure contexts cannot connect to secure workers, and secure contexts
     // cannot connect to non-secure workers:
-    if (host->instance()->creation_context_type() != creation_context_type) {
+    if (host->instance().creation_context_type() != creation_context_type) {
       client->OnScriptLoadFailed();
       return;
     }
@@ -181,8 +181,7 @@
       storage_partition_->browser_context(), site_instance->GetSiteURL(),
       /*can_be_default=*/true, &storage_domain, &partition_name, &in_memory);
 
-  CreateWorker(std::move(instance),
-               std::move(outside_fetch_client_settings_object),
+  CreateWorker(instance, std::move(outside_fetch_client_settings_object),
                std::move(client), client_process_id, frame_id, storage_domain,
                message_port, std::move(blob_url_loader_factory));
 }
@@ -197,7 +196,7 @@
 }
 
 void SharedWorkerServiceImpl::CreateWorker(
-    std::unique_ptr<SharedWorkerInstance> instance,
+    const SharedWorkerInstance& instance,
     blink::mojom::FetchClientSettingsObjectPtr
         outside_fetch_client_settings_object,
     blink::mojom::SharedWorkerClientPtr client,
@@ -208,14 +207,14 @@
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!IsShuttingDown(RenderProcessHost::FromID(client_process_id)));
-  DCHECK(!blob_url_loader_factory || instance->url().SchemeIsBlob());
+  DCHECK(!blob_url_loader_factory || instance.url().SchemeIsBlob());
 
   // Create the host. We need to do this even before starting the worker,
   // because we are about to bounce to the IO thread. If another ConnectToWorker
   // request arrives in the meantime, it finds and reuses the host instead of
   // creating a new host and therefore new SharedWorker thread.
-  auto host = std::make_unique<SharedWorkerHost>(this, std::move(instance),
-                                                 client_process_id);
+  auto host =
+      std::make_unique<SharedWorkerHost>(this, instance, client_process_id);
   auto weak_host = host->AsWeakPtr();
   worker_hosts_.insert(std::move(host));
 
@@ -242,8 +241,8 @@
   url::Origin origin(render_frame_host->frame_tree_node()->current_origin());
 
   WorkerScriptFetchInitiator::Start(
-      weak_host->worker_process_id(), weak_host->instance()->url(),
-      weak_host->instance()->constructor_origin(),
+      weak_host->worker_process_id(), weak_host->instance().url(),
+      weak_host->instance().constructor_origin(),
       net::NetworkIsolationKey(origin, origin), credentials_mode,
       std::move(outside_fetch_client_settings_object),
       ResourceType::kSharedWorker, service_worker_context_,
@@ -251,13 +250,13 @@
       std::move(blob_url_loader_factory), url_loader_factory_override_,
       storage_partition_, storage_domain,
       base::BindOnce(&SharedWorkerServiceImpl::DidCreateScriptLoader,
-                     weak_factory_.GetWeakPtr(), std::move(instance), weak_host,
+                     weak_factory_.GetWeakPtr(), instance, weak_host,
                      std::move(client), client_process_id, frame_id,
                      message_port));
 }
 
 void SharedWorkerServiceImpl::DidCreateScriptLoader(
-    std::unique_ptr<SharedWorkerInstance> instance,
+    const SharedWorkerInstance& instance,
     base::WeakPtr<SharedWorkerHost> host,
     blink::mojom::SharedWorkerClientPtr client,
     int process_id,
@@ -282,15 +281,14 @@
   // TODO(https://crbug.com/986188): Check if the main script's final response
   // URL is commitable.
 
-  StartWorker(std::move(instance), std::move(host), std::move(client),
-              process_id, frame_id, message_port,
-              std::move(subresource_loader_factories),
+  StartWorker(instance, std::move(host), std::move(client), process_id,
+              frame_id, message_port, std::move(subresource_loader_factories),
               std::move(main_script_load_params), std::move(controller),
               std::move(controller_service_worker_object_host));
 }
 
 void SharedWorkerServiceImpl::StartWorker(
-    std::unique_ptr<SharedWorkerInstance> instance,
+    const SharedWorkerInstance& instance,
     base::WeakPtr<SharedWorkerHost> host,
     blink::mojom::SharedWorkerClientPtr client,
     int client_process_id,
@@ -333,7 +331,7 @@
 SharedWorkerHost* SharedWorkerServiceImpl::FindAvailableSharedWorkerHost(
     const SharedWorkerInstance& instance) {
   for (auto& host : worker_hosts_) {
-    if (host->IsAvailable() && host->instance()->Matches(instance))
+    if (host->IsAvailable() && host->instance().Matches(instance))
       return host.get();
   }
   return nullptr;
diff --git a/content/browser/worker_host/shared_worker_service_impl.h b/content/browser/worker_host/shared_worker_service_impl.h
index 553f1de..f64da12 100644
--- a/content/browser/worker_host/shared_worker_service_impl.h
+++ b/content/browser/worker_host/shared_worker_service_impl.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <set>
+#include <string>
 #include <utility>
 
 #include "base/compiler_specific.h"
@@ -81,7 +82,7 @@
 
   // Creates a new worker in the client's renderer process.
   void CreateWorker(
-      std::unique_ptr<SharedWorkerInstance> instance,
+      const SharedWorkerInstance& instance,
       blink::mojom::FetchClientSettingsObjectPtr
           outside_fetch_client_settings_object,
       blink::mojom::SharedWorkerClientPtr client,
@@ -91,7 +92,7 @@
       const blink::MessagePortChannel& message_port,
       scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory);
   void DidCreateScriptLoader(
-      std::unique_ptr<SharedWorkerInstance> instance,
+      const SharedWorkerInstance& instance,
       base::WeakPtr<SharedWorkerHost> host,
       blink::mojom::SharedWorkerClientPtr client,
       int client_process_id,
@@ -105,7 +106,7 @@
           controller_service_worker_object_host,
       bool success);
   void StartWorker(
-      std::unique_ptr<SharedWorkerInstance> instance,
+      const SharedWorkerInstance& instance,
       base::WeakPtr<SharedWorkerHost> host,
       blink::mojom::SharedWorkerClientPtr client,
       int client_process_id,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 55c790b..f7cab03 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -48,6 +48,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom-forward.h"
+#include "services/service_manager/public/cpp/binder_map.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/cpp/manifest.h"
@@ -918,6 +919,12 @@
       service_manager::BinderRegistry* registry,
       RenderFrameHost* render_frame_host) {}
 
+  // Allows to register browser interfaces exposed through the RenderFrameHost.
+  // This mechanism will replace interface registries and binders used for
+  // handling InterfaceProvider's GetInterface() calls (see crbug.com/718652).
+  virtual void RegisterBrowserInterfaceBindersForFrame(
+      service_manager::BinderMapWithContext<RenderFrameHost*>* map) {}
+
   // Content was unable to bind a request for this interface, so the embedder
   // should try.
   virtual void BindInterfaceRequestFromFrame(
diff --git a/content/public/browser/shared_worker_service.h b/content/public/browser/shared_worker_service.h
index 0d09919..f36eb14 100644
--- a/content/public/browser/shared_worker_service.h
+++ b/content/public/browser/shared_worker_service.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_BROWSER_SHARED_WORKER_SERVICE_H_
 #define CONTENT_PUBLIC_BROWSER_SHARED_WORKER_SERVICE_H_
 
+#include <string>
+
 namespace url {
 class Origin;
 }  // namespace url
diff --git a/content/renderer/accessibility/ax_image_annotator.cc b/content/renderer/accessibility/ax_image_annotator.cc
index 2f68cce..cc95c6c 100644
--- a/content/renderer/accessibility/ax_image_annotator.cc
+++ b/content/renderer/accessibility/ax_image_annotator.cc
@@ -29,10 +29,10 @@
 AXImageAnnotator::AXImageAnnotator(
     RenderAccessibilityImpl* const render_accessibility,
     const std::string& preferred_language,
-    image_annotation::mojom::AnnotatorPtr annotator_ptr)
+    mojo::PendingRemote<image_annotation::mojom::Annotator> annotator)
     : render_accessibility_(render_accessibility),
       preferred_language_(preferred_language),
-      annotator_ptr_(std::move(annotator_ptr)) {
+      annotator_(std::move(annotator)) {
   DCHECK(render_accessibility_);
 }
 
@@ -82,10 +82,10 @@
   image_annotations_.emplace(image.AxID(), image);
   ImageInfo& image_info = image_annotations_.at(image.AxID());
   // Fetch image annotation.
-  annotator_ptr_->AnnotateImage(
-      image_id, preferred_language_, image_info.GetImageProcessor(),
-      base::BindOnce(&AXImageAnnotator::OnImageAnnotated,
-                     weak_factory_.GetWeakPtr(), image));
+  annotator_->AnnotateImage(image_id, preferred_language_,
+                            image_info.GetImageProcessor(),
+                            base::BindOnce(&AXImageAnnotator::OnImageAnnotated,
+                                           weak_factory_.GetWeakPtr(), image));
   VLOG(1) << "Requesting annotation for " << image_id << " with language '"
           << preferred_language_ << "' from page " << GetDocumentUrl();
 }
@@ -99,10 +99,10 @@
 
   ImageInfo& image_info = image_annotations_.at(image.AxID());
   // Update annotation.
-  annotator_ptr_->AnnotateImage(
-      image_id, preferred_language_, image_info.GetImageProcessor(),
-      base::BindOnce(&AXImageAnnotator::OnImageAnnotated,
-                     weak_factory_.GetWeakPtr(), image));
+  annotator_->AnnotateImage(image_id, preferred_language_,
+                            image_info.GetImageProcessor(),
+                            base::BindOnce(&AXImageAnnotator::OnImageAnnotated,
+                                           weak_factory_.GetWeakPtr(), image));
 }
 
 void AXImageAnnotator::OnImageRemoved(blink::WebAXObject& image) {
diff --git a/content/renderer/accessibility/ax_image_annotator.h b/content/renderer/accessibility/ax_image_annotator.h
index 6b1165e..264316d 100644
--- a/content/renderer/accessibility/ax_image_annotator.h
+++ b/content/renderer/accessibility/ax_image_annotator.h
@@ -15,6 +15,7 @@
 #include "base/optional.h"
 #include "content/common/content_export.h"
 #include "content/renderer/accessibility/render_accessibility_impl.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/image_annotation/public/cpp/image_processor.h"
 #include "services/image_annotation/public/mojom/image_annotation.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -36,9 +37,10 @@
 // owns it to update the relevant image annotations.
 class CONTENT_EXPORT AXImageAnnotator : public base::CheckedObserver {
  public:
-  AXImageAnnotator(RenderAccessibilityImpl* const render_accessibility,
-                   const std::string& preferred_language,
-                   image_annotation::mojom::AnnotatorPtr annotator_ptr);
+  AXImageAnnotator(
+      RenderAccessibilityImpl* const render_accessibility,
+      const std::string& preferred_language,
+      mojo::PendingRemote<image_annotation::mojom::Annotator> annotator);
   ~AXImageAnnotator() override;
 
   void Destroy();
@@ -122,7 +124,7 @@
   std::string preferred_language_;
 
   // A pointer to the automatic image annotation service.
-  image_annotation::mojom::AnnotatorPtr annotator_ptr_;
+  mojo::Remote<image_annotation::mojom::Annotator> annotator_;
 
   // Keeps track of the image data and the automatic annotations for each image.
   //
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index f66bdeb..e0ab923 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -1029,10 +1029,9 @@
 void RenderAccessibilityImpl::CreateAXImageAnnotator() {
   if (!render_frame_)
     return;
-
-  image_annotation::mojom::AnnotatorPtr annotator_ptr;
-  render_frame()->GetRemoteInterfaces()->GetInterface(
-      mojo::MakeRequest(&annotator_ptr));
+  mojo::PendingRemote<image_annotation::mojom::Annotator> annotator;
+  render_frame()->GetBrowserInterfaceBrokerProxy()->GetInterface(
+      annotator.InitWithNewPipeAndPassReceiver());
 
   const std::string preferred_language =
       render_frame()->render_view()
@@ -1040,7 +1039,7 @@
                 render_frame()->render_view()->GetAcceptLanguages())
           : std::string();
   ax_image_annotator_ = std::make_unique<AXImageAnnotator>(
-      this, preferred_language, std::move(annotator_ptr));
+      this, preferred_language, std::move(annotator));
   tree_source_.AddImageAnnotator(ax_image_annotator_.get());
 }
 
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index 2ceac8e3..35dab50 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -26,6 +26,8 @@
 #include "content/renderer/accessibility/ax_image_annotator.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_view_impl.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ppapi/c/private/ppp_pdf.h"
 #include "services/image_annotation/public/cpp/image_processor.h"
 #include "services/image_annotation/public/mojom/image_annotation.mojom.h"
@@ -68,11 +70,12 @@
 
 class TestAXImageAnnotator : public AXImageAnnotator {
  public:
-  TestAXImageAnnotator(TestRenderAccessibilityImpl* const render_accessibility,
-                       image_annotation::mojom::AnnotatorPtr annotator_ptr)
+  TestAXImageAnnotator(
+      TestRenderAccessibilityImpl* const render_accessibility,
+      mojo::PendingRemote<image_annotation::mojom::Annotator> annotator)
       : AXImageAnnotator(render_accessibility,
                          std::string() /* preferred_language */,
-                         std::move(annotator_ptr)) {}
+                         std::move(annotator)) {}
   ~TestAXImageAnnotator() override = default;
 
  private:
@@ -98,10 +101,10 @@
   MockAnnotationService() = default;
   ~MockAnnotationService() override = default;
 
-  image_annotation::mojom::AnnotatorPtr GetPtr() {
-    image_annotation::mojom::AnnotatorPtr ptr;
-    bindings_.AddBinding(this, mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<image_annotation::mojom::Annotator> GetRemote() {
+    mojo::PendingRemote<image_annotation::mojom::Annotator> remote;
+    receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
+    return remote;
   }
 
   void AnnotateImage(const std::string& image_id,
@@ -126,7 +129,7 @@
     image_processors_[index].reset();
   }
 
-  mojo::BindingSet<image_annotation::mojom::Annotator> bindings_;
+  mojo::ReceiverSet<image_annotation::mojom::Annotator> receivers_;
 
   DISALLOW_COPY_AND_ASSIGN(MockAnnotationService);
 };
@@ -660,7 +663,7 @@
     SetMode(mode);
     render_accessibility().ax_image_annotator_ =
         std::make_unique<TestAXImageAnnotator>(&render_accessibility(),
-                                               mock_annotator().GetPtr());
+                                               mock_annotator().GetRemote());
     render_accessibility().tree_source_.RemoveImageAnnotator();
     render_accessibility().tree_source_.AddImageAnnotator(
         render_accessibility().ax_image_annotator_.get());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 91b5179e..9ca541c3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2261,6 +2261,7 @@
       "//build/config/freetype",
       "//components/download/internal/common:internal_java",
       "//content/public/android:content_java",
+      "//gpu/ipc/common:android_texture_owner_test_support",
       "//media/capture/content/android",
       "//media/capture/content/android:screen_capture_java",
       "//third_party/blink/public/common",
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 5012aa3..bc220cd 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -354,10 +354,7 @@
 crbug.com/990368 [ mac passthrough ] conformance/canvas/draw-static-webgl-to-multiple-canvas-test.html [ Failure ]
 crbug.com/990368 [ mac passthrough ] conformance/canvas/draw-webgl-to-canvas-test.html [ Failure ]
 crbug.com/990368 [ mac passthrough ] conformance/canvas/to-data-url-test.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/context/context-hidden-alpha.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/context/context-no-alpha-fbo-with-alpha.html [ Failure ]
+crbug.com/angleproject/3812 [ mac passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ]
 crbug.com/990368 [ mac passthrough ] conformance/context/premultiplyalpha-test.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/extensions/oes-texture-float-with-video.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/extensions/oes-texture-half-float-with-video.html [ Failure ]
@@ -367,17 +364,13 @@
 crbug.com/angleproject/3769 [ mac passthrough ] conformance/glsl/misc/shader-with-short-circuiting-operators.html [ Failure ]
 crbug.com/angleproject/3771 [ mac passthrough ] conformance/glsl/samplers/glsl-function-texture2dprojlod.html [ Failure ]
 crbug.com/angleproject/3770 [ mac passthrough ] conformance/ogles/GL/build/build_177_to_178.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/rendering/color-mask-preserved-during-implicit-clears.html [ Failure ]
 crbug.com/angleproject/3772 [ mac passthrough ] conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/rendering/scissor-rect-repeated-rendering.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/textures/image_bitmap_from_video/* [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/textures/video/* [ Failure ]
 crbug.com/990368 [ mac passthrough ] conformance/textures/webgl_canvas/* [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/textures/misc/copy-tex-image-2d-formats.html [ Failure ]
 crbug.com/angleproject/3774 [ mac passthrough ] conformance/textures/misc/gl-pixelstorei.html [ Failure ]
 crbug.com/angleproject/3766 [ mac passthrough ] conformance/textures/misc/gl-teximage.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/textures/misc/tex-image-webgl.html [ Failure ]
-crbug.com/angleproject/3766 [ mac passthrough ] conformance/textures/misc/tex-input-validation.html [ Failure ]
+crbug.com/angleproject/3813 [ mac passthrough ] conformance/textures/misc/tex-image-webgl.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ]
 crbug.com/989194 [ mac passthrough ] conformance/textures/misc/texture-npot-video.html [ Failure ]
diff --git a/extensions/common/extension_messages.cc b/extensions/common/extension_messages.cc
index b067beed..1edd698 100644
--- a/extensions/common/extension_messages.cc
+++ b/extensions/common/extension_messages.cc
@@ -139,10 +139,7 @@
   // schemes after parsing the pattern. Update these method calls once we can
   // ignore scheme validation with URLPattern parse options. crbug.com/90544
   p->SetValidSchemes(URLPattern::SCHEME_ALL);
-  // Allow effective TLD wildcarding since this check is only needed on initial
-  // creation of URLPattern and not as part of deserialization.
-  URLPattern::ParseResult result =
-      p->Parse(spec, URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD);
+  URLPattern::ParseResult result = p->Parse(spec);
   p->SetValidSchemes(valid_schemes);
   return URLPattern::ParseResult::kSuccess == result;
 }
diff --git a/extensions/common/extension_messages_unittest.cc b/extensions/common/extension_messages_unittest.cc
index 07c0d5e..208436d 100644
--- a/extensions/common/extension_messages_unittest.cc
+++ b/extensions/common/extension_messages_unittest.cc
@@ -42,7 +42,7 @@
 
 void AddPattern(const std::string& pattern, URLPatternSet* extent) {
   URLPattern parsed(URLPattern::SCHEME_ALL);
-  parsed.Parse(pattern, URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD);
+  parsed.Parse(pattern);
   extent->AddPattern(parsed);
 }
 
@@ -75,7 +75,7 @@
                          URLPatternSet(), URLPatternSet()));
   }
   URLPatternSet runtime_blocked_hosts;
-  AddPattern("*://*.example.*/*", &runtime_blocked_hosts);
+  AddPattern("*://*.example.com/*", &runtime_blocked_hosts);
   URLPatternSet runtime_allowed_hosts;
   AddPattern("*://good.example.com/*", &runtime_allowed_hosts);
   extension->permissions_data()->SetPolicyHostRestrictions(
diff --git a/extensions/common/url_pattern.cc b/extensions/common/url_pattern.cc
index e9fc1e281..91663db 100644
--- a/extensions/common/url_pattern.cc
+++ b/extensions/common/url_pattern.cc
@@ -144,14 +144,12 @@
     : valid_schemes_(SCHEME_NONE),
       match_all_urls_(false),
       match_subdomains_(false),
-      match_effective_tld_(true),
       port_("*") {}
 
 URLPattern::URLPattern(int valid_schemes)
     : valid_schemes_(valid_schemes),
       match_all_urls_(false),
       match_subdomains_(false),
-      match_effective_tld_(true),
       port_("*") {}
 
 URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
@@ -160,7 +158,6 @@
     : valid_schemes_(valid_schemes),
       match_all_urls_(false),
       match_subdomains_(false),
-      match_effective_tld_(true),
       port_("*") {
   ParseResult result = Parse(pattern);
   if (result != ParseResult::kSuccess) {
@@ -202,15 +199,9 @@
 }
 
 URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
-  return Parse(pattern, DENY_WILDCARD_FOR_EFFECTIVE_TLD);
-}
-
-URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern,
-                                          ParseOptions parse_options) {
   spec_.clear();
   SetMatchAllURLs(false);
   SetMatchSubdomains(false);
-  SetMatchEffectiveTld(true);
   SetPort("*");
 
   // Special case pattern to match every valid URL.
@@ -320,13 +311,6 @@
       host_components.erase(host_components.begin());
     }
 
-    // If explicitly allowed, the last component can optionally be '*' to
-    // match all effective TLDs.
-    if (parse_options == ALLOW_WILDCARD_FOR_EFFECTIVE_TLD &&
-        host_components.size() > 1 && host_components.back() == "*") {
-      match_effective_tld_ = false;
-      host_components.pop_back();
-    }
     host_ = base::JoinString(host_components, ".");
 
     path_start_pos = host_end_pos;
@@ -388,11 +372,6 @@
   match_subdomains_ = val;
 }
 
-void URLPattern::SetMatchEffectiveTld(bool val) {
-  spec_.clear();
-  match_effective_tld_ = val;
-}
-
 bool URLPattern::SetScheme(base::StringPiece scheme) {
   spec_.clear();
   scheme.CopyToString(&scheme_);
@@ -501,16 +480,6 @@
   base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
   const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
 
-  // If we don't care about matching the effective TLD, remove it.
-  if (!match_effective_tld_) {
-    int reg_length = net::registry_controlled_domains::GetRegistryLength(
-        test, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
-        net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
-    if (reg_length > 0) {
-      test_host = test_host.substr(0, test_host.size() - reg_length - 1);
-    }
-  }
-
   // If the hosts are exactly equal, we have a match.
   if (test_host == pattern_host)
     return true;
@@ -613,12 +582,6 @@
     if (!host_.empty())
       spec += host_;
 
-    if (!match_effective_tld_) {
-      if (!host_.empty())
-        spec += ".";
-      spec += "*";
-    }
-
     if (port_ != "*") {
       spec += ":";
       spec += port_;
@@ -661,9 +624,6 @@
 
 base::Optional<URLPattern> URLPattern::CreateIntersection(
     const URLPattern& other) const {
-  DCHECK(match_effective_tld_);
-  DCHECK(other.match_effective_tld_);
-
   // Easy case: Schemes don't overlap. Return nullopt.
   int intersection_schemes = URLPattern::SCHEME_NONE;
   if (valid_schemes_ == URLPattern::SCHEME_ALL)
diff --git a/extensions/common/url_pattern.h b/extensions/common/url_pattern.h
index fc5d41a..55fe6184 100644
--- a/extensions/common/url_pattern.h
+++ b/extensions/common/url_pattern.h
@@ -85,12 +85,6 @@
     kNumParseResults,
   };
 
-  // Types of URLPattern that Parse() considers valid.
-  enum ParseOptions {
-    DENY_WILDCARD_FOR_EFFECTIVE_TLD,
-    ALLOW_WILDCARD_FOR_EFFECTIVE_TLD,
-  };
-
   // The <all_urls> string pattern.
   static const char kAllUrlsPattern[];
 
@@ -121,10 +115,8 @@
   // Initializes this instance by parsing the provided string. Returns
   // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
   // On failure, this instance will have some intermediate values and is in an
-  // invalid state. If you want to allow the match pattern to specify a wildcard
-  // for the effective TLD, specify in |parse_options|.
+  // invalid state.
   ParseResult Parse(base::StringPiece pattern_str);
-  ParseResult Parse(base::StringPiece pattern_str, ParseOptions parse_options);
 
   // Gets the bitmask of valid schemes.
   int valid_schemes() const { return valid_schemes_; }
@@ -139,15 +131,6 @@
   bool match_subdomains() const { return match_subdomains_; }
   void SetMatchSubdomains(bool val);
 
-  // Gets whether host() contains an effective TLD. If false, during
-  // a match, the URL you're comparing must have its TLD removed
-  // prior to comparison.
-  // e.g. For the match pattern https://google.com/*
-  //      If this is true: host() would be google.com
-  //      If this is false: host() would be google
-  bool match_effective_tld() const { return match_effective_tld_; }
-  void SetMatchEffectiveTld(bool val);
-
   // Gets the path the pattern matches with the leading slash. This can have
   // embedded asterisks which are interpreted using glob rules.
   const std::string& path() const { return path_; }
@@ -229,7 +212,6 @@
   // For instance, given the patterns http://*.google.com/* and
   // *://maps.google.com/*, the intersection is http://maps.google.com/*.
   // NOTES:
-  // - This will DCHECK if either pattern has match_effective_tld_ set to false.
   // - Though scheme intersections are supported, the serialization of
   //   URLPatternSet does not record them. Be sure that this is safe for your
   //   use cases.
@@ -296,12 +278,6 @@
   // component of the pattern's host was "*".
   bool match_subdomains_;
 
-  // Whether we should match the effective TLD of the host. This is true by
-  // default and only false if ParseOptions is ALLOW_WILDCARD_FOR_EFFECTIVE_TLD
-  // and is only applicable when the the pattern's host ends with ".*"
-  // (e.g. https://example.*/*).
-  bool match_effective_tld_;
-
   // The port.
   std::string port_;
 
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc
index 993bd10..88514f0 100644
--- a/extensions/common/url_pattern_unittest.cc
+++ b/extensions/common/url_pattern_unittest.cc
@@ -88,14 +88,12 @@
       // Port-like strings in the path should not trigger a warning.
       {"http://*/:1234", URLPattern::ParseResult::kSuccess, "*"},
       {"http://*.foo/bar:1234", URLPattern::ParseResult::kSuccess, "*"},
-      {"http://foo/bar:1234/path", URLPattern::ParseResult::kSuccess, "*"},
-      {"http://*.foo.*/:1234", URLPattern::ParseResult::kSuccess, "*"}};
+      {"http://foo/bar:1234/path", URLPattern::ParseResult::kSuccess, "*"}};
 
   for (size_t i = 0; i < base::size(kTestPatterns); ++i) {
     URLPattern pattern(URLPattern::SCHEME_ALL);
     EXPECT_EQ(kTestPatterns[i].expected_result,
-              pattern.Parse(kTestPatterns[i].pattern,
-                            URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD))
+              pattern.Parse(kTestPatterns[i].pattern))
         << "Got unexpected result for URL pattern: "
         << kTestPatterns[i].pattern;
     EXPECT_EQ(kTestPatterns[i].expected_port, pattern.port())
@@ -167,7 +165,6 @@
   EXPECT_EQ("http", pattern.scheme());
   EXPECT_EQ("", pattern.host());
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com")));
@@ -184,7 +181,6 @@
   EXPECT_EQ("https", pattern.scheme());
   EXPECT_EQ("", pattern.host());
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/foo*", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foo")));
@@ -203,7 +199,6 @@
   EXPECT_EQ("http", pattern.scheme());
   EXPECT_EQ("google.com", pattern.host());
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/foo*bar", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar")));
@@ -225,7 +220,6 @@
   EXPECT_EQ("file", pattern.scheme());
   EXPECT_EQ("", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/foo?bar\\*baz", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo?bar\\hellobaz")));
@@ -240,7 +234,6 @@
   EXPECT_EQ("http", pattern.scheme());
   EXPECT_EQ("127.0.0.1", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
@@ -256,7 +249,6 @@
   // Canonicalization forces 0.0.1 to 0.0.0.1.
   EXPECT_EQ("0.0.0.1", pattern.host());
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   // Subdomain matching is never done if the argument has an IP address host.
@@ -273,7 +265,6 @@
   EXPECT_EQ("http", pattern.scheme());
   EXPECT_EQ("xn--gkd", pattern.host());
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/a%C2%81%E1*", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(
@@ -290,7 +281,6 @@
   EXPECT_EQ(content::kChromeUIScheme, pattern.scheme());
   EXPECT_EQ("favicon", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(
@@ -310,7 +300,6 @@
   EXPECT_FALSE(pattern.MatchesScheme("file"));
   EXPECT_FALSE(pattern.MatchesScheme("ftp"));
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
@@ -331,7 +320,6 @@
   EXPECT_TRUE(pattern.MatchesScheme("filesystem"));
   EXPECT_TRUE(pattern.MatchesScheme(extensions::kExtensionScheme));
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_TRUE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(
@@ -368,7 +356,6 @@
   EXPECT_TRUE(pattern.MatchesScheme("about"));
   EXPECT_TRUE(pattern.MatchesScheme(extensions::kExtensionScheme));
   EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_TRUE(pattern.match_all_urls());
   EXPECT_EQ("/*", pattern.path());
   EXPECT_TRUE(
@@ -421,7 +408,6 @@
   EXPECT_EQ("", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
   EXPECT_FALSE(pattern.match_all_urls());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_EQ("/foo*", pattern.path());
   EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
   EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
@@ -438,7 +424,6 @@
   EXPECT_EQ("", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
   EXPECT_FALSE(pattern.match_all_urls());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_EQ("/foo*", pattern.path());
   EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
   EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
@@ -456,7 +441,6 @@
   // Since hostname is ignored for file://.
   EXPECT_EQ("", pattern.host());
   EXPECT_FALSE(pattern.match_subdomains());
-  EXPECT_TRUE(pattern.match_effective_tld());
   EXPECT_FALSE(pattern.match_all_urls());
   EXPECT_EQ("/foo*", pattern.path());
   EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
@@ -524,39 +508,6 @@
       GURL("filesystem:chrome-extension://ftw/t/file.txt")));
 }
 
-// effective TLD wildcard
-TEST(URLPatternTest, EffectiveTldWildcard) {
-  URLPattern pattern(kAllSchemes);
-  EXPECT_EQ(URLPattern::ParseResult::kSuccess,
-            pattern.Parse("http://*.google.*/foo*bar",
-                          URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD));
-  EXPECT_EQ("http", pattern.scheme());
-  EXPECT_EQ("google", pattern.host());
-  EXPECT_TRUE(pattern.match_subdomains());
-  EXPECT_FALSE(pattern.match_effective_tld());
-  EXPECT_FALSE(pattern.match_all_urls());
-  EXPECT_EQ("/foo*bar", pattern.path());
-  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar")));
-  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com.br/foo?bar")));
-  EXPECT_TRUE(
-      pattern.MatchesURL(GURL("http://monkey.images.google.co.uk/foooobar")));
-  EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar")));
-  EXPECT_TRUE(pattern.MatchesURL(GURL("filesystem:http://google.com/foo/bar")));
-  EXPECT_FALSE(pattern.MatchesURL(
-      GURL("filesystem:http://google.com/temporary/foobar")));
-  URLPattern pattern_sub(kAllSchemes);
-  EXPECT_EQ(URLPattern::ParseResult::kSuccess,
-            pattern_sub.Parse("https://maps.google.*/",
-                              URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD));
-  EXPECT_EQ("https", pattern_sub.scheme());
-  EXPECT_EQ("maps.google", pattern_sub.host());
-  EXPECT_FALSE(pattern_sub.match_subdomains());
-  EXPECT_FALSE(pattern_sub.match_all_urls());
-  EXPECT_EQ("/", pattern_sub.path());
-  EXPECT_TRUE(pattern_sub.MatchesURL(GURL("https://maps.google.co.uk/")));
-  EXPECT_FALSE(pattern_sub.MatchesURL(GURL("https://sub.maps.google.co.uk/")));
-}
-
 static const struct GetAsStringPatterns {
   const std::string pattern;
 } kGetAsStringTestCases[] = {
diff --git a/gpu/command_buffer/service/gr_cache_controller_unittest.cc b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
index 0deb744a..f70344e 100644
--- a/gpu/command_buffer/service/gr_cache_controller_unittest.cc
+++ b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
@@ -72,7 +72,7 @@
     SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
     ASSERT_TRUE(bm.tryAllocPixels(info));
     sk_sp<SkImage> uploaded =
-        SkImage::MakeFromBitmap(bm)->makeTextureImage(gr_context(), nullptr);
+        SkImage::MakeFromBitmap(bm)->makeTextureImage(gr_context());
     ASSERT_TRUE(uploaded);
   }
   EXPECT_GT(gr_context()->getResourceCachePurgeableBytes(), 0u);
@@ -94,7 +94,7 @@
     SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
     ASSERT_TRUE(bm.tryAllocPixels(info));
     sk_sp<SkImage> uploaded =
-        SkImage::MakeFromBitmap(bm)->makeTextureImage(gr_context(), nullptr);
+        SkImage::MakeFromBitmap(bm)->makeTextureImage(gr_context());
     ASSERT_TRUE(uploaded);
   }
   EXPECT_GT(gr_context()->getResourceCachePurgeableBytes(), 0u);
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index 25c3366..49c798f 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -142,17 +142,12 @@
 
   if (is_android) {
     sources += [
-      "android/scoped_surface_request_conduit.cc",
-      "android/scoped_surface_request_conduit.h",
-      "android/surface_owner_android.cc",
-      "android/surface_owner_android.h",
       "gpu_surface_lookup.cc",
       "gpu_surface_lookup.h",
       "gpu_surface_tracker.cc",
       "gpu_surface_tracker.h",
     ]
     libs = [ "android" ]
-    deps += [ ":android_image_reader_utils" ]
   }
 
   if (use_ozone) {
@@ -178,6 +173,78 @@
   }
 }
 
+if (is_android) {
+  component("android_texture_owner") {
+    sources = [
+      "android/image_reader_gl_owner.cc",
+      "android/image_reader_gl_owner.h",
+      "android/scoped_surface_request_conduit.cc",
+      "android/scoped_surface_request_conduit.h",
+      "android/surface_texture_gl_owner.cc",
+      "android/surface_texture_gl_owner.h",
+      "android/texture_owner.cc",
+      "android/texture_owner.h",
+    ]
+    configs += [ "//gpu:gpu_implementation" ]
+    deps = [
+      ":android_image_reader_utils",
+      "//base",
+      "//gpu/command_buffer/service:gles2_sources",
+      "//gpu/command_buffer/service:service_sources",
+      "//ui/gl",
+    ]
+    libs = [ "android" ]
+    visibility = [
+      "//gpu/*",
+      "//media/gpu:gpu",
+      "//content/browser:browser",
+    ]
+  }
+}
+
+if (is_android) {
+  jumbo_static_library("android_texture_owner_test_support") {
+    testonly = true
+    sources = [
+      "android/mock_abstract_texture.cc",
+      "android/mock_abstract_texture.h",
+      "android/mock_texture_owner.cc",
+      "android/mock_texture_owner.h",
+    ]
+    deps = [
+      ":android_texture_owner",
+      "//base/test:test_support",
+      "//gpu:test_support",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//ui/gl",
+      "//ui/gl/init",
+    ]
+  }
+}
+
+if (is_android) {
+  source_set("android_texture_owner_unittests") {
+    testonly = true
+    sources = [
+      "android/image_reader_gl_owner_unittest.cc",
+      "android/surface_texture_gl_owner_unittest.cc",
+    ]
+
+    deps = [
+      ":android_texture_owner",
+      ":android_texture_owner_test_support",
+      "//base/test:test_support",
+      "//gpu:test_support",
+      "//media/base:base",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//ui/gl",
+      "//ui/gl/init",
+    ]
+  }
+}
+
 # Depend on this to use surface_handle.h without pulling in all of gpu ipc.
 source_set("surface_handle_type") {
   public = [
diff --git a/gpu/ipc/common/DEPS b/gpu/ipc/common/DEPS
index 3725d16..418e224 100644
--- a/gpu/ipc/common/DEPS
+++ b/gpu/ipc/common/DEPS
@@ -5,4 +5,5 @@
   "+mojo",
   "+ui/base",
   "+ui/latency",
+  "+media/base/media_switches.h",
 ]
diff --git a/media/gpu/android/image_reader_gl_owner.cc b/gpu/ipc/common/android/image_reader_gl_owner.cc
similarity index 95%
rename from media/gpu/android/image_reader_gl_owner.cc
rename to gpu/ipc/common/android/image_reader_gl_owner.cc
index c5c14d0..56014b15 100644
--- a/media/gpu/android/image_reader_gl_owner.cc
+++ b/gpu/ipc/common/android/image_reader_gl_owner.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 "media/gpu/android/image_reader_gl_owner.h"
+#include "gpu/ipc/common/android/image_reader_gl_owner.h"
 
 #include <android/native_window_jni.h>
 #include <jni.h>
@@ -25,7 +25,7 @@
 #include "ui/gl/scoped_binders.h"
 #include "ui/gl/scoped_make_current.h"
 
-namespace media {
+namespace gpu {
 
 namespace {
 bool IsSurfaceControl(TextureOwner::Mode mode) {
@@ -76,7 +76,7 @@
 };
 
 ImageReaderGLOwner::ImageReaderGLOwner(
-    std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+    std::unique_ptr<gles2::AbstractTexture> texture,
     Mode mode)
     : TextureOwner(false /* binds_texture_on_image_update */,
                    std::move(texture)),
@@ -117,7 +117,7 @@
   if (return_code != AMEDIA_OK) {
     LOG(ERROR) << " Image reader creation failed.";
     if (return_code == AMEDIA_ERROR_INVALID_PARAMETER)
-      LOG(ERROR) << "Either reader is NULL, or one or more of width, height, "
+      LOG(ERROR) << "Either reader is null, or one or more of width, height, "
                     "format, maxImages arguments is not supported";
     else
       LOG(ERROR) << "unknown error";
@@ -152,7 +152,7 @@
   DCHECK_EQ(image_refs_.size(), 0u);
 }
 
-void ImageReaderGLOwner::OnTextureDestroyed(gpu::gles2::AbstractTexture*) {
+void ImageReaderGLOwner::OnTextureDestroyed(gles2::AbstractTexture*) {
   // The AbstractTexture is being destroyed.  This can happen if, for example,
   // the video decoder's gl context is lost.  Remember that the platform texture
   // might not be gone; it's possible for the gl decoder (and AbstractTexture)
@@ -165,7 +165,7 @@
   DCHECK(image_reader_);
 
   // Now we can stop listening to new images.
-  loader_.AImageReader_setImageListener(image_reader_, NULL);
+  loader_.AImageReader_setImageListener(image_reader_, nullptr);
 
   // Delete all images before closing the associated image reader.
   for (auto& image_ref : image_refs_)
@@ -183,6 +183,7 @@
 
 void ImageReaderGLOwner::SetFrameAvailableCallback(
     const base::RepeatingClosure& frame_available_cb) {
+  DCHECK(!frame_available_cb_);
   frame_available_cb_ = std::move(frame_available_cb);
 }
 
@@ -241,7 +242,7 @@
   // just return if error occurs.
   switch (return_code) {
     case AMEDIA_ERROR_INVALID_PARAMETER:
-      LOG(ERROR) << " Image is NULL";
+      LOG(ERROR) << " Image is null";
       base::UmaHistogramSparse("Media.AImageReaderGLOwner.AcquireImageResult",
                                return_code);
       return;
@@ -397,7 +398,7 @@
   // If there is no |image_reader_|, we are in tear down so no fence is
   // required.
   if (image_bound_ && texture_owner_->image_reader_)
-    release_fence = gpu::CreateEglFenceAndExportFd();
+    release_fence = CreateEglFenceAndExportFd();
   else
     release_fence = std::move(ready_fence_);
   texture_owner_->ReleaseRefOnImage(image_, std::move(release_fence));
@@ -413,15 +414,15 @@
     return;
 
   // Insert an EGL fence and make server wait for image to be available.
-  if (!gpu::InsertEglFenceAndWait(GetReadyFence()))
+  if (!InsertEglFenceAndWait(GetReadyFence()))
     return;
 
   // Create EGL image from the AImage and bind it to the texture.
-  if (!gpu::CreateAndBindEglImage(image_, texture_owner_->GetTextureId(),
-                                  &texture_owner_->loader_))
+  if (!CreateAndBindEglImage(image_, texture_owner_->GetTextureId(),
+                             &texture_owner_->loader_))
     return;
 
   image_bound_ = true;
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/image_reader_gl_owner.h b/gpu/ipc/common/android/image_reader_gl_owner.h
similarity index 90%
rename from media/gpu/android/image_reader_gl_owner.h
rename to gpu/ipc/common/android/image_reader_gl_owner.h
index 397f45a..bc661310 100644
--- a/media/gpu/android/image_reader_gl_owner.h
+++ b/gpu/ipc/common/android/image_reader_gl_owner.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_ANDROID_IMAGE_READER_GL_OWNER_H_
-#define MEDIA_GPU_ANDROID_IMAGE_READER_GL_OWNER_H_
+#ifndef GPU_IPC_COMMON_ANDROID_IMAGE_READER_GL_OWNER_H_
+#define GPU_IPC_COMMON_ANDROID_IMAGE_READER_GL_OWNER_H_
 
 #include <memory>
 
 #include "base/android/android_image_reader_compat.h"
 #include "base/containers/flat_map.h"
-#include "media/gpu/android/texture_owner.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "ui/gl/gl_fence_egl.h"
 #include "ui/gl/gl_image_ahardwarebuffer.h"
 
@@ -19,7 +19,7 @@
 }  // namespace android
 }  // namespace base
 
-namespace media {
+namespace gpu {
 
 // This class wraps the AImageReader usage and is used to create a GL texture
 // using the current platform GL context and returns a new ImageReaderGLOwner
@@ -27,7 +27,7 @@
 // decoded media frames. Media frames can update the attached surface handle
 // with image data and this class helps to create an eglImage using that image
 // data present in the surface.
-class MEDIA_GPU_EXPORT ImageReaderGLOwner : public TextureOwner {
+class GPU_EXPORT ImageReaderGLOwner : public TextureOwner {
  public:
   gl::GLContext* GetContext() const override;
   gl::GLSurface* GetSurface() const override;
@@ -45,7 +45,7 @@
   int32_t max_images_for_testing() const { return max_images_; }
 
  protected:
-  void OnTextureDestroyed(gpu::gles2::AbstractTexture*) override;
+  void OnTextureDestroyed(gles2::AbstractTexture*) override;
 
  private:
   friend class TextureOwner;
@@ -74,7 +74,7 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedCurrentImageRef);
   };
 
-  ImageReaderGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+  ImageReaderGLOwner(std::unique_ptr<gles2::AbstractTexture> texture,
                      Mode secure_mode);
   ~ImageReaderGLOwner() override;
 
@@ -130,6 +130,6 @@
   DISALLOW_COPY_AND_ASSIGN(ImageReaderGLOwner);
 };
 
-}  // namespace media
+}  // namespace gpu
 
-#endif  // MEDIA_GPU_ANDROID_IMAGE_READER_GL_OWNER_H_
+#endif  // GPU_IPC_COMMON_ANDROID_IMAGE_READER_GL_OWNER_H_
diff --git a/media/gpu/android/image_reader_gl_owner_unittest.cc b/gpu/ipc/common/android/image_reader_gl_owner_unittest.cc
similarity index 96%
rename from media/gpu/android/image_reader_gl_owner_unittest.cc
rename to gpu/ipc/common/android/image_reader_gl_owner_unittest.cc
index 3c10602..f13ce719 100644
--- a/media/gpu/android/image_reader_gl_owner_unittest.cc
+++ b/gpu/ipc/common/android/image_reader_gl_owner_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/android/texture_owner.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 
 #include <stdint.h>
 #include <memory>
@@ -11,16 +11,16 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "gpu/command_buffer/service/abstract_texture.h"
+#include "gpu/ipc/common/android/image_reader_gl_owner.h"
+#include "gpu/ipc/common/android/mock_abstract_texture.h"
 #include "media/base/media_switches.h"
-#include "media/gpu/android/image_reader_gl_owner.h"
-#include "media/gpu/android/mock_abstract_texture.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/init/gl_factory.h"
 
-namespace media {
+namespace gpu {
 
 class ImageReaderGLOwnerTest : public testing::Test {
  public:
@@ -202,4 +202,4 @@
             3);
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/mock_abstract_texture.cc b/gpu/ipc/common/android/mock_abstract_texture.cc
similarity index 84%
rename from media/gpu/android/mock_abstract_texture.cc
rename to gpu/ipc/common/android/mock_abstract_texture.cc
index 2adda1f..f8cfe4c 100644
--- a/media/gpu/android/mock_abstract_texture.cc
+++ b/gpu/ipc/common/android/mock_abstract_texture.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/android/mock_abstract_texture.h"
+#include "gpu/ipc/common/android/mock_abstract_texture.h"
 
-namespace media {
+namespace gpu {
 
 MockAbstractTexture::MockAbstractTexture() = default;
 
@@ -16,4 +16,4 @@
 
 MockAbstractTexture::~MockAbstractTexture() = default;
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/mock_abstract_texture.h b/gpu/ipc/common/android/mock_abstract_texture.h
similarity index 87%
rename from media/gpu/android/mock_abstract_texture.h
rename to gpu/ipc/common/android/mock_abstract_texture.h
index 737c95f9..4419c7c9f 100644
--- a/media/gpu/android/mock_abstract_texture.h
+++ b/gpu/ipc/common/android/mock_abstract_texture.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
-#define MEDIA_GPU_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
+#ifndef GPU_IPC_COMMON_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
+#define GPU_IPC_COMMON_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
 
 #include "base/memory/weak_ptr.h"
 #include "gpu/command_buffer/service/abstract_texture.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-namespace media {
+namespace gpu {
 
 // SupportsWeakPtr so it's easy to tell when it has been destroyed.
 class MockAbstractTexture
@@ -40,6 +40,6 @@
   CleanupCallback cleanup_callback_;
 };
 
-}  // namespace media
+}  // namespace gpu
 
-#endif  // MEDIA_GPU_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
+#endif  // GPU_IPC_COMMON_ANDROID_MOCK_ABSTRACT_TEXTURE_H_
diff --git a/media/gpu/android/mock_texture_owner.cc b/gpu/ipc/common/android/mock_texture_owner.cc
similarity index 88%
rename from media/gpu/android/mock_texture_owner.cc
rename to gpu/ipc/common/android/mock_texture_owner.cc
index 3aefd5a..428b8ef 100644
--- a/media/gpu/android/mock_texture_owner.cc
+++ b/gpu/ipc/common/android/mock_texture_owner.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/android/mock_texture_owner.h"
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 
-#include "media/gpu/android/mock_abstract_texture.h"
+#include "gpu/ipc/common/android/mock_abstract_texture.h"
 
-namespace media {
+namespace gpu {
 
 using testing::Invoke;
 using testing::Return;
@@ -33,4 +33,4 @@
   ClearAbstractTexture();
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/mock_texture_owner.h b/gpu/ipc/common/android/mock_texture_owner.h
similarity index 86%
rename from media/gpu/android/mock_texture_owner.h
rename to gpu/ipc/common/android/mock_texture_owner.h
index 3c92743..595c2138 100644
--- a/media/gpu/android/mock_texture_owner.h
+++ b/gpu/ipc/common/android/mock_texture_owner.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_ANDROID_MOCK_TEXTURE_OWNER_H_
-#define MEDIA_GPU_ANDROID_MOCK_TEXTURE_OWNER_H_
+#ifndef GPU_IPC_COMMON_ANDROID_MOCK_TEXTURE_OWNER_H_
+#define GPU_IPC_COMMON_ANDROID_MOCK_TEXTURE_OWNER_H_
 
 #include <memory>
 
 #include "base/android/scoped_hardware_buffer_fence_sync.h"
-#include "media/gpu/android/texture_owner.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_bindings.h"
@@ -17,7 +17,7 @@
 
 using testing::NiceMock;
 
-namespace media {
+namespace gpu {
 
 // This is a mock with a small amount of fake functionality too.
 class MockTextureOwner : public TextureOwner {
@@ -53,6 +53,6 @@
   ~MockTextureOwner();
 };
 
-}  // namespace media
+}  // namespace gpu
 
-#endif  // MEDIA_GPU_ANDROID_MOCK_TEXTURE_OWNER_H_
+#endif  // GPU_IPC_COMMON_ANDROID_MOCK_TEXTURE_OWNER_H_
diff --git a/gpu/ipc/common/android/scoped_surface_request_conduit.h b/gpu/ipc/common/android/scoped_surface_request_conduit.h
index 2ccbaf0..994cd55 100644
--- a/gpu/ipc/common/android/scoped_surface_request_conduit.h
+++ b/gpu/ipc/common/android/scoped_surface_request_conduit.h
@@ -6,7 +6,7 @@
 #define GPU_IPC_COMMON_ANDROID_SCOPED_SURFACE_REQUEST_CONDUIT_H_
 
 #include "gpu/gpu_export.h"
-#include "gpu/ipc/common/android/surface_owner_android.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 
 namespace base {
 class UnguessableToken;
@@ -14,7 +14,7 @@
 
 namespace gpu {
 
-// Allows the forwarding of SurfaceOwners from the GPU or the browser process
+// Allows the forwarding of TextureOwners from the GPU or the browser process
 // to fulfill requests registered by the ScopedSurfaceRequestManager.
 class GPU_EXPORT ScopedSurfaceRequestConduit {
  public:
@@ -25,7 +25,7 @@
   // process, to fulfill the request registered under the |request_token| key.
   virtual void ForwardSurfaceOwnerForSurfaceRequest(
       const base::UnguessableToken& request_token,
-      const SurfaceOwner* surface_owner) = 0;
+      const TextureOwner* texture_owner) = 0;
 
  protected:
   virtual ~ScopedSurfaceRequestConduit() {}
diff --git a/gpu/ipc/common/android/surface_owner_android.cc b/gpu/ipc/common/android/surface_owner_android.cc
deleted file mode 100644
index 9faa7a4..0000000
--- a/gpu/ipc/common/android/surface_owner_android.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// 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 "gpu/ipc/common/android/surface_owner_android.h"
-
-#include "base/android/jni_android.h"
-#include "base/feature_list.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "gpu/config/gpu_finch_features.h"
-#include "gpu/ipc/common/android/android_image_reader_utils.h"
-#include "ui/gl/android/surface_texture.h"
-#include "ui/gl/gl_fence_android_native_fence_sync.h"
-#include "ui/gl/gl_image_ahardwarebuffer.h"
-
-namespace gpu {
-namespace {
-
-// Surface Texture based implementation.
-class SurfaceTexture : public SurfaceOwner {
- public:
-  explicit SurfaceTexture(uint32_t texture_id);
-  ~SurfaceTexture() override;
-
-  void SetFrameAvailableCallback(
-      const base::RepeatingClosure& callback) override;
-  gl::ScopedJavaSurface CreateJavaSurface() const override;
-  void GetTransformMatrix(float mtx[16]) override;
-  void UpdateTexImage() override;
-
- private:
-  scoped_refptr<gl::SurfaceTexture> surface_texture_;
-
-  DISALLOW_COPY_AND_ASSIGN(SurfaceTexture);
-};
-
-SurfaceTexture::SurfaceTexture(uint32_t texture_id)
-    : surface_texture_(gl::SurfaceTexture::Create(texture_id)) {}
-
-void SurfaceTexture::SetFrameAvailableCallback(
-    const base::RepeatingClosure& callback) {
-  surface_texture_->SetFrameAvailableCallback(callback);
-}
-
-gl::ScopedJavaSurface SurfaceTexture::CreateJavaSurface() const {
-  return gl::ScopedJavaSurface(surface_texture_.get());
-}
-
-void SurfaceTexture::GetTransformMatrix(float mtx[]) {
-  surface_texture_->GetTransformMatrix(mtx);
-}
-
-void SurfaceTexture::UpdateTexImage() {
-  surface_texture_->UpdateTexImage();
-}
-
-SurfaceTexture::~SurfaceTexture() = default;
-
-// ImageReader based implementation.
-class ImageReader : public SurfaceOwner {
- public:
-  explicit ImageReader(uint32_t texture_id);
-  ~ImageReader() override;
-
-  void SetFrameAvailableCallback(
-      const base::RepeatingClosure& callback) override;
-  gl::ScopedJavaSurface CreateJavaSurface() const override;
-  void GetTransformMatrix(float mtx[16]) override;
-  void UpdateTexImage() override;
-
- private:
-  static void CallbackSignal(void* context, AImageReader* reader);
-
-  // AImageReader instance
-  AImageReader* image_reader_ = nullptr;
-
-  // Image which was last acquired by the image reader. This needs to be saved
-  // so that it can be deleted later.
-  AImage* current_image_ = nullptr;
-
-  GLuint texture_id_;
-
-  // reference to the class instance which is used to dynamically
-  // load the functions in android libraries at runtime.
-  base::android::AndroidImageReader& loader_;
-
-  // Frame available callback handling. ImageListner registered with
-  // AImageReader is notified when there is a new frame available which
-  // in turns runs the callback function on correct thread using task_runner.
-  base::RepeatingClosure callback_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageReader);
-};
-
-ImageReader::ImageReader(GLuint texture_id)
-    : texture_id_(texture_id),
-      loader_(base::android::AndroidImageReader::GetInstance()) {
-  // Set the width, height and format to some default value. This parameters
-  // are/maybe overriden by the producer sending buffers to this imageReader's
-  // Surface.
-  // Note that max_images should be as small as possible to limit the memory
-  // usage. ImageReader needs 2 images to mimic the behavior of SurfaceTexture.
-  // Also note that we always acquire an image before deleting the
-  // previous acquired image. This causes 2 acquired images to be in flight at
-  // the image acquisition point until the previous image is deleted.
-  int32_t width = 1, height = 1, max_images = 2;
-  AIMAGE_FORMATS format = AIMAGE_FORMAT_YUV_420_888;
-  AImageReader* reader = nullptr;
-  // The usage flag below should be used when the buffer will be read from by
-  // the GPU as a texture.
-  const uint64_t usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
-
-  // Create a new reader for images of the desired size and format.
-  media_status_t return_code = loader_.AImageReader_newWithUsage(
-      width, height, format, usage, max_images, &reader);
-  if (return_code != AMEDIA_OK) {
-    LOG(ERROR) << " Image reader creation failed.";
-    if (return_code == AMEDIA_ERROR_INVALID_PARAMETER) {
-      LOG(ERROR)
-          << "Either reader is nullptr, or one or more of width, height, "
-             "format, maxImages arguments is not supported";
-    } else
-      LOG(ERROR) << "unknown error";
-    return;
-  }
-  DCHECK(reader);
-  image_reader_ = reader;
-}
-
-// This callback function will be called when there is a new image available
-// for in the image reader's queue.
-void ImageReader::CallbackSignal(void* context, AImageReader* reader) {
-  ImageReader* image_reader_ptr = reinterpret_cast<ImageReader*>(context);
-  if (image_reader_ptr->task_runner_->BelongsToCurrentThread()) {
-    image_reader_ptr->callback_.Run();
-  } else {
-    image_reader_ptr->task_runner_->PostTask(FROM_HERE,
-                                             image_reader_ptr->callback_);
-  }
-}
-
-void ImageReader::SetFrameAvailableCallback(
-    const base::RepeatingClosure& callback) {
-  callback_ = callback;
-  task_runner_ = base::ThreadTaskRunnerHandle::Get();
-
-  // Create a new Image Listner.
-  AImageReader_ImageListener listener;
-  listener.context = reinterpret_cast<void*>(this);
-  listener.onImageAvailable = &ImageReader::CallbackSignal;
-
-  // Set the onImageAvailable listener of this image reader.
-  if (loader_.AImageReader_setImageListener(image_reader_, &listener) !=
-      AMEDIA_OK) {
-    LOG(ERROR) << " Failed to register AImageReader listener";
-    return;
-  }
-}
-
-ImageReader::~ImageReader() {
-  loader_.AImageReader_setImageListener(image_reader_, nullptr);
-
-  // Delete the image before closing the associated image reader.
-  if (current_image_)
-    loader_.AImage_delete(current_image_);
-
-  // Delete the image reader.
-  loader_.AImageReader_delete(image_reader_);
-}
-
-gl::ScopedJavaSurface ImageReader::CreateJavaSurface() const {
-  // Get the android native window from the image reader.
-  ANativeWindow* window = nullptr;
-  if (loader_.AImageReader_getWindow(image_reader_, &window) != AMEDIA_OK) {
-    LOG(ERROR) << "unable to get a window from image reader.";
-    return gl::ScopedJavaSurface::AcquireExternalSurface(nullptr);
-  }
-
-  // Get the java surface object from the Android native window.
-  JNIEnv* env = base::android::AttachCurrentThread();
-  jobject j_surface = loader_.ANativeWindow_toSurface(env, window);
-  DCHECK(j_surface);
-
-  // Get the scoped java surface that is owned externally.
-  return gl::ScopedJavaSurface::AcquireExternalSurface(j_surface);
-}
-
-void ImageReader::UpdateTexImage() {
-  DCHECK(image_reader_);
-
-  // Acquire the latest image asynchronously
-  AImage* image = nullptr;
-  int acquire_fence_fd = -1;
-  media_status_t return_code = AMEDIA_OK;
-
-  // This method duplicates the fence file descriptor and the caller is
-  // responsible for closing the returend file descriptor.
-  // We now use AcquireNextImageAsync() instead of AcquireLatestImageAsync()
-  // because AcquireLatestImageAsync() only works when
-  // max_images-number_of_acquired_images >= 2. This is now not true for our
-  // AImageReader use case with max_images=2 since we always have one previously
-  // acquired image when we try to acquire a new image.
-  return_code = loader_.AImageReader_acquireNextImageAsync(
-      image_reader_, &image, &acquire_fence_fd);
-
-  // Log the error return code.
-  if (return_code != AMEDIA_OK) {
-    base::UmaHistogramSparse("GPU.SurfaceOwner.AImageReader.AcquireImageResult",
-                             return_code);
-  }
-
-  // TODO(http://crbug.com/846050).
-  // Need to add some better error handling if below error occurs. Currently we
-  // just return if error occurs.
-  switch (return_code) {
-    case AMEDIA_ERROR_INVALID_PARAMETER:
-      LOG(ERROR) << " Image is nullptr";
-      return;
-    case AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED:
-      LOG(ERROR)
-          << "number of concurrently acquired images has reached the limit";
-      return;
-    case AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE:
-      LOG(ERROR) << "no buffers currently available in the reader queue";
-      return;
-    case AMEDIA_ERROR_UNKNOWN:
-      LOG(ERROR) << "method fails for some other reasons";
-      return;
-    case AMEDIA_OK:
-      // Method call succeeded.
-      break;
-    default:
-      // No other error code should be returned.
-      NOTREACHED();
-      return;
-  }
-  base::ScopedFD scoped_acquire_fence_fd(acquire_fence_fd);
-
-  // If there is no new image simply return. At this point previous image will
-  // still be bound to the texture.
-  if (!image) {
-    return;
-  }
-
-  // If we have a new Image, delete the previously acquired image.
-  if (!gpu::DeleteAImageAsync(current_image_, &loader_))
-    return;
-
-  // Make the newly acuired image as current image.
-  current_image_ = image;
-
-  if (!gpu::InsertEglFenceAndWait(std::move(scoped_acquire_fence_fd)))
-    return;
-
-  // Create EGL image from the AImage and bind it to the texture.
-  if (!gpu::CreateAndBindEglImage(current_image_, texture_id_, &loader_))
-    return;
-}
-
-void ImageReader::GetTransformMatrix(float mtx[]) {
-  // Assign a Y inverted Identity matrix. MediaPlayer path performs a Y
-  // inversion of this matrix later. Hence if we assign a Y inverted matrix
-  // here, it simply becomes an identity matrix later and will have no effect
-  // on the image data.
-  static constexpr float kYInvertedIdentity[16]{1, 0, 0, 0, 0, -1, 0, 0,
-                                                0, 0, 1, 0, 0, 1,  0, 1};
-  memcpy(mtx, kYInvertedIdentity, sizeof(kYInvertedIdentity));
-}
-
-}  // anonymous namespace
-
-// Interface definitions.
-SurfaceOwner::SurfaceOwner() = default;
-SurfaceOwner::~SurfaceOwner() = default;
-
-// Static.
-std::unique_ptr<SurfaceOwner> SurfaceOwner::Create(uint32_t texture_id) {
-  // Use AImageReader if its supported and is enabled by the feature flag.
-  if (base::android::AndroidImageReader::GetInstance().IsSupported() &&
-      base::FeatureList::IsEnabled(features::kAImageReaderMediaPlayer)) {
-    return std::make_unique<ImageReader>(texture_id);
-  }
-
-  // If not, fall back to legacy path of using SurfaceTexture.
-  return std::make_unique<SurfaceTexture>(texture_id);
-}
-
-}  // namespace gpu
diff --git a/gpu/ipc/common/android/surface_owner_android.h b/gpu/ipc/common/android/surface_owner_android.h
deleted file mode 100644
index 00943ffb..0000000
--- a/gpu/ipc/common/android/surface_owner_android.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 GPU_IPC_COMMON_ANDROID_SURFACE_OWNER_ANDROID_H_
-#define GPU_IPC_COMMON_ANDROID_SURFACE_OWNER_ANDROID_H_
-
-#include <memory>
-
-#include "base/android/android_image_reader_compat.h"
-#include "base/memory/ref_counted.h"
-#include "gpu/gpu_export.h"
-#include "ui/gl/android/scoped_java_surface.h"
-
-namespace gpu {
-
-// This interface wraps the usage of surface and the associated OpenGL
-// texture_id. Surface owned by this class is used by OpenGL, MediaPlayer or
-// CameraDevice to draw into. Once a frame is drawn into the surface, the
-// associated callback function is run. The drawn frame can be used to update
-// the GL texture at target texture_id.
-class GPU_EXPORT SurfaceOwner {
- public:
-  virtual ~SurfaceOwner();
-
-  // Creates a new SurfaceOwner with the provided texture id. This texture_id
-  // target will be updated when UpdateTexImage() is called.
-  static std::unique_ptr<SurfaceOwner> Create(uint32_t texture_id);
-
-  // Set the callback function to run when a new frame is available.
-  virtual void SetFrameAvailableCallback(
-      const base::RepeatingClosure& callback) = 0;
-
-  // Create a java surface for the SurfaceOwner.
-  virtual gl::ScopedJavaSurface CreateJavaSurface() const = 0;
-
-  // Transformation matrix if any associated with the texture image.
-  virtual void GetTransformMatrix(float mtx[16]) = 0;
-
-  // Update the texture image using the latest available image data.
-  virtual void UpdateTexImage() = 0;
-
- protected:
-  SurfaceOwner();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SurfaceOwner);
-};
-
-}  // namespace gpu
-
-#endif  // GPU_IPC_COMMON_ANDROID_SURFACE_OWNER_ANDROID_H_
diff --git a/media/gpu/android/surface_texture_gl_owner.cc b/gpu/ipc/common/android/surface_texture_gl_owner.cc
similarity index 90%
rename from media/gpu/android/surface_texture_gl_owner.cc
rename to gpu/ipc/common/android/surface_texture_gl_owner.cc
index 83daac2..5d9e154 100644
--- a/media/gpu/android/surface_texture_gl_owner.cc
+++ b/gpu/ipc/common/android/surface_texture_gl_owner.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 "media/gpu/android/surface_texture_gl_owner.h"
+#include "gpu/ipc/common/android/surface_texture_gl_owner.h"
 
 #include <memory>
 
@@ -17,10 +17,10 @@
 #include "ui/gl/scoped_binders.h"
 #include "ui/gl/scoped_make_current.h"
 
-namespace media {
+namespace gpu {
 
 SurfaceTextureGLOwner::SurfaceTextureGLOwner(
-    std::unique_ptr<gpu::gles2::AbstractTexture> texture)
+    std::unique_ptr<gles2::AbstractTexture> texture)
     : TextureOwner(true /*binds_texture_on_update */, std::move(texture)),
       surface_texture_(gl::SurfaceTexture::Create(GetTextureId())),
       context_(gl::GLContext::GetCurrent()),
@@ -37,7 +37,7 @@
   ClearAbstractTexture();
 }
 
-void SurfaceTextureGLOwner::OnTextureDestroyed(gpu::gles2::AbstractTexture*) {
+void SurfaceTextureGLOwner::OnTextureDestroyed(gles2::AbstractTexture*) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // Make sure that the SurfaceTexture isn't using the GL objects.
@@ -46,8 +46,11 @@
 
 void SurfaceTextureGLOwner::SetFrameAvailableCallback(
     const base::RepeatingClosure& frame_available_cb) {
+  DCHECK(!is_frame_available_callback_set_);
+
   // Setting the callback to be run from any thread since |frame_available_cb|
   // is thread safe.
+  is_frame_available_callback_set_ = true;
   surface_texture_->SetFrameAvailableCallbackOnAnyThread(frame_available_cb);
 }
 
@@ -98,4 +101,4 @@
   return nullptr;
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/surface_texture_gl_owner.h b/gpu/ipc/common/android/surface_texture_gl_owner.h
similarity index 73%
rename from media/gpu/android/surface_texture_gl_owner.h
rename to gpu/ipc/common/android/surface_texture_gl_owner.h
index b3f5b716..1b5b5fb2 100644
--- a/media/gpu/android/surface_texture_gl_owner.h
+++ b/gpu/ipc/common/android/surface_texture_gl_owner.h
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
-#define MEDIA_GPU_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
+#ifndef GPU_IPC_COMMON_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
+#define GPU_IPC_COMMON_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
 
-#include "media/gpu/android/texture_owner.h"
-
-#include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "media/gpu/media_gpu_export.h"
+#include "gpu/gpu_export.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "ui/gl/android/surface_texture.h"
 
 namespace base {
@@ -18,7 +16,7 @@
 }  // namespace android
 }  // namespace base
 
-namespace media {
+namespace gpu {
 
 // This class wraps the Surface Texture usage. It is used to create a surface
 // texture attached to a new texture of the current platform GL context. The
@@ -26,7 +24,7 @@
 // frames. Media frames can update the attached surface handle with image data.
 // This class helps to update the attached texture using that image data
 // present in the surface.
-class MEDIA_GPU_EXPORT SurfaceTextureGLOwner : public TextureOwner {
+class GPU_EXPORT SurfaceTextureGLOwner : public TextureOwner {
  public:
   gl::GLContext* GetContext() const override;
   gl::GLSurface* GetSurface() const override;
@@ -41,23 +39,27 @@
   GetAHardwareBuffer() override;
 
  protected:
-  void OnTextureDestroyed(gpu::gles2::AbstractTexture*) override;
+  void OnTextureDestroyed(gles2::AbstractTexture*) override;
 
  private:
   friend class TextureOwner;
 
-  SurfaceTextureGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture);
+  SurfaceTextureGLOwner(std::unique_ptr<gles2::AbstractTexture> texture);
   ~SurfaceTextureGLOwner() override;
 
   scoped_refptr<gl::SurfaceTexture> surface_texture_;
+
   // The context and surface that were used to create |surface_texture_|.
   scoped_refptr<gl::GLContext> context_;
   scoped_refptr<gl::GLSurface> surface_;
 
+  // To ensure that SetFrameAvailableCallback() is called only once.
+  bool is_frame_available_callback_set_ = false;
+
   THREAD_CHECKER(thread_checker_);
   DISALLOW_COPY_AND_ASSIGN(SurfaceTextureGLOwner);
 };
 
-}  // namespace media
+}  // namespace gpu
 
-#endif  // MEDIA_GPU_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
+#endif  // GPU_IPC_COMMON_ANDROID_SURFACE_TEXTURE_GL_OWNER_H_
diff --git a/media/gpu/android/surface_texture_gl_owner_unittest.cc b/gpu/ipc/common/android/surface_texture_gl_owner_unittest.cc
similarity index 96%
rename from media/gpu/android/surface_texture_gl_owner_unittest.cc
rename to gpu/ipc/common/android/surface_texture_gl_owner_unittest.cc
index 9eace9c..ed91bd1 100644
--- a/media/gpu/android/surface_texture_gl_owner_unittest.cc
+++ b/gpu/ipc/common/android/surface_texture_gl_owner_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/android/surface_texture_gl_owner.h"
+#include "gpu/ipc/common/android/surface_texture_gl_owner.h"
 
 #include <stdint.h>
 
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/test/scoped_task_environment.h"
-#include "media/gpu/android/mock_abstract_texture.h"
+#include "gpu/ipc/common/android/mock_abstract_texture.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_bindings.h"
@@ -21,11 +21,11 @@
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/init/gl_factory.h"
 
+using testing::_;
 using testing::Invoke;
 using testing::NiceMock;
-using testing::_;
 
-namespace media {
+namespace gpu {
 
 class SurfaceTextureGLOwnerTest : public testing::Test {
  public:
@@ -125,4 +125,4 @@
   new_surface = nullptr;
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/texture_owner.cc b/gpu/ipc/common/android/texture_owner.cc
similarity index 76%
rename from media/gpu/android/texture_owner.cc
rename to gpu/ipc/common/android/texture_owner.cc
index da02e54..6bb9428998 100644
--- a/media/gpu/android/texture_owner.cc
+++ b/gpu/ipc/common/android/texture_owner.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 "media/gpu/android/texture_owner.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 
 #include <memory>
 
@@ -14,14 +14,14 @@
 #include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/texture_base.h"
-#include "media/gpu/android/image_reader_gl_owner.h"
-#include "media/gpu/android/surface_texture_gl_owner.h"
+#include "gpu/ipc/common/android/image_reader_gl_owner.h"
+#include "gpu/ipc/common/android/surface_texture_gl_owner.h"
 #include "ui/gl/scoped_binders.h"
 
-namespace media {
+namespace gpu {
 
 TextureOwner::TextureOwner(bool binds_texture_on_update,
-                           std::unique_ptr<gpu::gles2::AbstractTexture> texture)
+                           std::unique_ptr<gles2::AbstractTexture> texture)
     : base::RefCountedDeleteOnSequence<TextureOwner>(
           base::ThreadTaskRunnerHandle::Get()),
       binds_texture_on_update_(binds_texture_on_update),
@@ -41,7 +41,7 @@
 
 // static
 scoped_refptr<TextureOwner> TextureOwner::Create(
-    std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+    std::unique_ptr<gles2::AbstractTexture> texture,
     Mode mode) {
   switch (mode) {
     case Mode::kAImageReaderInsecure:
@@ -57,18 +57,18 @@
 }
 
 // static
-std::unique_ptr<gpu::gles2::AbstractTexture> TextureOwner::CreateTexture(
-    scoped_refptr<gpu::SharedContextState> context_state) {
+std::unique_ptr<gles2::AbstractTexture> TextureOwner::CreateTexture(
+    scoped_refptr<SharedContextState> context_state) {
   DCHECK(context_state);
 
-  gpu::gles2::FeatureInfo* feature_info = context_state->feature_info();
+  gles2::FeatureInfo* feature_info = context_state->feature_info();
   if (feature_info && feature_info->is_passthrough_cmd_decoder()) {
     return std::make_unique<
-        gpu::gles2::AbstractTextureImplOnSharedContextPassthrough>(
+        gles2::AbstractTextureImplOnSharedContextPassthrough>(
         GL_TEXTURE_EXTERNAL_OES, std::move(context_state));
   }
 
-  return std::make_unique<gpu::gles2::AbstractTextureImplOnSharedContext>(
+  return std::make_unique<gles2::AbstractTextureImplOnSharedContext>(
       GL_TEXTURE_EXTERNAL_OES, GL_RGBA,
       0,  // width
       0,  // height
@@ -81,7 +81,7 @@
   return texture_->service_id();
 }
 
-gpu::TextureBase* TextureOwner::GetTextureBase() const {
+TextureBase* TextureOwner::GetTextureBase() const {
   return texture_->GetTextureBase();
 }
 
@@ -89,4 +89,4 @@
   texture_.reset();
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/media/gpu/android/texture_owner.h b/gpu/ipc/common/android/texture_owner.h
similarity index 84%
rename from media/gpu/android/texture_owner.h
rename to gpu/ipc/common/android/texture_owner.h
index f9c4a52..b4746cf 100644
--- a/media/gpu/android/texture_owner.h
+++ b/gpu/ipc/common/android/texture_owner.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_ANDROID_TEXTURE_OWNER_H_
-#define MEDIA_GPU_ANDROID_TEXTURE_OWNER_H_
+#ifndef GPU_IPC_COMMON_ANDROID_TEXTURE_OWNER_H_
+#define GPU_IPC_COMMON_ANDROID_TEXTURE_OWNER_H_
 
 #include <android/hardware_buffer.h>
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/single_thread_task_runner.h"
-#include "media/gpu/media_gpu_export.h"
+#include "gpu/gpu_export.h"
 #include "ui/gl/android/scoped_java_surface.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -29,9 +29,6 @@
 namespace gles2 {
 class AbstractTexture;
 }  // namespace gles2
-}  // namespace gpu
-
-namespace media {
 
 // A Texture wrapper interface that creates and maintains ownership of the
 // attached GL or Vulkan texture. The texture is destroyed with the object.
@@ -40,7 +37,7 @@
 // be called on any thread. It's safe to keep and drop refptrs to it on any
 // thread; it will be automatically destructed on the thread it was constructed
 // on.
-class MEDIA_GPU_EXPORT TextureOwner
+class GPU_EXPORT TextureOwner
     : public base::RefCountedDeleteOnSequence<TextureOwner> {
  public:
   // Creates a GL texture using the current platform GL context and returns a
@@ -57,12 +54,12 @@
     kSurfaceTextureInsecure
   };
   static scoped_refptr<TextureOwner> Create(
-      std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+      std::unique_ptr<gles2::AbstractTexture> texture,
       Mode mode);
 
   // Create a texture that's appropriate for a TextureOwner.
-  static std::unique_ptr<gpu::gles2::AbstractTexture> CreateTexture(
-      scoped_refptr<gpu::SharedContextState> context_state);
+  static std::unique_ptr<gles2::AbstractTexture> CreateTexture(
+      scoped_refptr<SharedContextState> context_state);
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
     return task_runner_;
@@ -70,7 +67,7 @@
 
   // Returns the GL texture id that the TextureOwner is attached to.
   GLuint GetTextureId() const;
-  gpu::TextureBase* GetTextureBase() const;
+  TextureBase* GetTextureBase() const;
   virtual gl::GLContext* GetContext() const = 0;
   virtual gl::GLSurface* GetSurface() const = 0;
 
@@ -95,23 +92,24 @@
   virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
   GetAHardwareBuffer() = 0;
 
+  // Set the callback function to run when a new frame is available.
+  // |frame_available_cb| is thread safe and can be called on any thread. This
+  // method should be called only once, i.e., once a callback is provided, it
+  // should not be changed.
+  virtual void SetFrameAvailableCallback(
+      const base::RepeatingClosure& frame_available_cb) = 0;
+
   bool binds_texture_on_update() const { return binds_texture_on_update_; }
 
  protected:
   friend class base::RefCountedDeleteOnSequence<TextureOwner>;
   friend class base::DeleteHelper<TextureOwner>;
-  friend class CodecBufferWaitCoordinator;
 
   // |texture| is the texture that we'll own.
   TextureOwner(bool binds_texture_on_update,
-               std::unique_ptr<gpu::gles2::AbstractTexture> texture);
+               std::unique_ptr<gles2::AbstractTexture> texture);
   virtual ~TextureOwner();
 
-  // Set the callback function to run when a new frame is available.
-  // |frame_available_cb| is thread safe and can be called on any thread.
-  virtual void SetFrameAvailableCallback(
-      const base::RepeatingClosure& frame_available_cb) = 0;
-
   // Drop |texture_| immediately.  Will call OnTextureDestroyed immediately if
   // it hasn't been called before (e.g., due to lost context).
   // Subclasses must call this before they complete destruction, else
@@ -121,21 +119,21 @@
 
   // Called when |texture_| signals that the platform texture will be destroyed.
   // See AbstractTexture::SetCleanupCallback.
-  virtual void OnTextureDestroyed(gpu::gles2::AbstractTexture*) = 0;
+  virtual void OnTextureDestroyed(gles2::AbstractTexture*) = 0;
 
-  gpu::gles2::AbstractTexture* texture() const { return texture_.get(); }
+  gles2::AbstractTexture* texture() const { return texture_.get(); }
 
  private:
   // Set to true if the updating the image for this owner will automatically
   // bind it to the texture target.
   const bool binds_texture_on_update_;
 
-  std::unique_ptr<gpu::gles2::AbstractTexture> texture_;
+  std::unique_ptr<gles2::AbstractTexture> texture_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(TextureOwner);
 };
 
-}  // namespace media
+}  // namespace gpu
 
-#endif  // MEDIA_GPU_ANDROID_TEXTURE_OWNER_H_
+#endif  // GPU_IPC_COMMON_ANDROID_TEXTURE_OWNER_H_
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 96851a363..3e12ed6 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -115,6 +115,7 @@
       "stream_texture_android.h",
     ]
     libs += [ "android" ]
+    public_deps += [ "//gpu/ipc/common:android_texture_owner" ]
   }
   if (is_linux) {
     sources += [ "image_transport_surface_linux.cc" ]
diff --git a/gpu/ipc/service/DEPS b/gpu/ipc/service/DEPS
index b333190..d335ceef8 100644
--- a/gpu/ipc/service/DEPS
+++ b/gpu/ipc/service/DEPS
@@ -13,4 +13,5 @@
   "+ui/latency",
   "+ui/ozone",
   "+ui/platform_window",
+  "+media/gpu/android/texture_owner.h",
 ]
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index c538c62..1552c03f7 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -6,7 +6,10 @@
 
 #include <string.h>
 
+#include "base/android/android_image_reader_compat.h"
 #include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/command_buffer/service/abstract_texture_impl_shared_context_state.h"
@@ -16,6 +19,7 @@
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/shared_image_factory.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
 #include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
@@ -28,6 +32,7 @@
 
 namespace gpu {
 namespace {
+
 std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrent(
     SharedContextState* context_state) {
   std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current;
@@ -39,6 +44,20 @@
   return scoped_make_current;
 }
 
+TextureOwner::Mode GetTextureOwnerMode() {
+  const bool a_image_reader_supported =
+      base::android::AndroidImageReader::GetInstance().IsSupported();
+
+  // TODO(vikassoni) : Currently we have 2 different flags to enable/disable
+  // AImageReader - one for MCVD and other for MediaPlayer here. Merge those 2
+  // flags into a single flag. Keeping the 2 flags separate for now since finch
+  // experiment using this flag is in progress.
+  return a_image_reader_supported && base::FeatureList::IsEnabled(
+                                         features::kAImageReaderMediaPlayer)
+             ? TextureOwner::Mode::kAImageReaderInsecure
+             : TextureOwner::Mode::kSurfaceTextureInsecure;
+}
+
 class SharedImageBackingStreamTexture : public gpu::SharedImageBacking {
  public:
   SharedImageBackingStreamTexture(
@@ -89,22 +108,30 @@
   if (result != ContextResult::kSuccess)
     return nullptr;
   auto scoped_make_current = MakeCurrent(context_state.get());
-  auto texture = std::make_unique<gles2::AbstractTextureImplOnSharedContext>(
-      GL_TEXTURE_EXTERNAL_OES, GL_RGBA, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-      context_state.get());
-  return new StreamTexture(channel, stream_id, std::move(texture),
-                           std::move(context_state));
+  return new StreamTexture(channel, stream_id, std::move(context_state));
 }
 
-StreamTexture::StreamTexture(
-    GpuChannel* channel,
-    int32_t route_id,
-    std::unique_ptr<gles2::AbstractTexture> surface_owner_texture,
-    scoped_refptr<SharedContextState> context_state)
-    : surface_owner_texture_(std::move(surface_owner_texture)),
-      surface_owner_texture_id_(
-          surface_owner_texture_->GetTextureBase()->service_id()),
-      surface_owner_(SurfaceOwner::Create(surface_owner_texture_id_)),
+// static
+void StreamTexture::RunCallback(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    base::WeakPtr<StreamTexture> weak_stream_texture) {
+  if (task_runner->BelongsToCurrentThread()) {
+    if (weak_stream_texture)
+      weak_stream_texture->OnFrameAvailable();
+  } else {
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(&StreamTexture::RunCallback, std::move(task_runner),
+                       std::move(weak_stream_texture)));
+  }
+}
+
+StreamTexture::StreamTexture(GpuChannel* channel,
+                             int32_t route_id,
+                             scoped_refptr<SharedContextState> context_state)
+    : texture_owner_(
+          TextureOwner::Create(TextureOwner::CreateTexture(context_state),
+                               GetTextureOwnerMode())),
       size_(0, 0),
       has_pending_frame_(false),
       channel_(channel),
@@ -122,8 +149,10 @@
   context_state_->AddContextLostObserver(this);
   memset(current_matrix_, 0, sizeof(current_matrix_));
   channel->AddRoute(route_id, sequence_, this);
-  surface_owner_->SetFrameAvailableCallback(base::BindRepeating(
-      &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr()));
+
+  texture_owner_->SetFrameAvailableCallback(base::BindRepeating(
+      &StreamTexture::RunCallback, base::ThreadTaskRunnerHandle::Get(),
+      weak_factory_.GetWeakPtr()));
 }
 
 StreamTexture::~StreamTexture() {
@@ -145,27 +174,31 @@
 
 // gpu::gles2::GLStreamTextureMatrix implementation
 void StreamTexture::GetTextureMatrix(float xform[16]) {
-  if (surface_owner_) {
+  if (texture_owner_) {
     UpdateTexImage();
-    surface_owner_->GetTransformMatrix(current_matrix_);
+    texture_owner_->GetTransformMatrix(current_matrix_);
   }
   memcpy(xform, current_matrix_, sizeof(current_matrix_));
   YInvertMatrix(xform);
 }
 
 void StreamTexture::OnContextLost() {
-  surface_owner_ = nullptr;
+  texture_owner_ = nullptr;
 }
 
 void StreamTexture::UpdateTexImage() {
-  DCHECK(surface_owner_.get());
+  DCHECK(texture_owner_.get());
 
   if (!has_pending_frame_) return;
 
   auto scoped_make_current = MakeCurrent(context_state_.get());
   gl::ScopedTextureBinder scoped_bind_texture(GL_TEXTURE_EXTERNAL_OES,
-                                              surface_owner_texture_id_);
-  surface_owner_->UpdateTexImage();
+                                              texture_owner_->GetTextureId());
+  texture_owner_->UpdateTexImage();
+
+  // Binds the egl image to the texture_id if its not already bound.
+  if (!texture_owner_->binds_texture_on_update())
+    texture_owner_->EnsureTexImageBound();
   has_pending_frame_ = false;
 }
 
@@ -173,7 +206,7 @@
   if (target != GL_TEXTURE_EXTERNAL_OES)
     return false;
 
-  if (!surface_owner_.get())
+  if (!texture_owner_.get())
     return false;
 
   GLint texture_id;
@@ -185,7 +218,7 @@
   // glGetIntegerv() parameter. In this case the value of |texture_id| will be
   // zero and we assume that it is properly bound to |texture_id_|.
   if (texture_id > 0 &&
-      static_cast<unsigned>(texture_id) != surface_owner_texture_id_)
+      static_cast<unsigned>(texture_id) != texture_owner_->GetTextureId())
     return false;
 
   UpdateTexImage();
@@ -236,7 +269,7 @@
 
   ScopedSurfaceRequestConduit::GetInstance()
       ->ForwardSurfaceOwnerForSurfaceRequest(request_token,
-                                             surface_owner_.get());
+                                             texture_owner_.get());
 }
 
 void StreamTexture::OnCreateSharedImage(const gpu::Mailbox& mailbox,
@@ -245,14 +278,14 @@
   DCHECK(channel_);
   size_ = size;
 
-  if (!surface_owner_)
+  if (!texture_owner_)
     return;
 
-  // We do not update |surface_owner_texture_|'s internal gles2::Texture's
+  // We do not update |texture_owner_texture_|'s internal gles2::Texture's
   // size. This is because the gles2::Texture is never used directly, the
-  // associated |surface_owner_texture_id_| being the only part of that object
+  // associated |texture_owner_texture_id_| being the only part of that object
   // we interact with.
-  // If we ever use |surface_owner_texture_|, we need to ensure that it gets
+  // If we ever use |texture_owner_texture_|, we need to ensure that it gets
   // updated here.
 
   auto scoped_make_current = MakeCurrent(context_state_.get());
@@ -260,8 +293,8 @@
       std::make_unique<gles2::AbstractTextureImplOnSharedContext>(
           GL_TEXTURE_EXTERNAL_OES, GL_RGBA, size.width(), size.height(), 1, 0,
           GL_RGBA, GL_UNSIGNED_BYTE, context_state_.get());
-  legacy_mailbox_texture->BindStreamTextureImage(this,
-                                                 surface_owner_texture_id_);
+  legacy_mailbox_texture->BindStreamTextureImage(
+      this, texture_owner_->GetTextureId());
 
   auto shared_image = std::make_unique<SharedImageBackingStreamTexture>(
       mailbox, size_, std::move(legacy_mailbox_texture));
diff --git a/gpu/ipc/service/stream_texture_android.h b/gpu/ipc/service/stream_texture_android.h
index a53251a..1a9cb265 100644
--- a/gpu/ipc/service/stream_texture_android.h
+++ b/gpu/ipc/service/stream_texture_android.h
@@ -15,7 +15,7 @@
 #include "base/unguessable_token.h"
 #include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
-#include "gpu/ipc/common/android/surface_owner_android.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "ipc/ipc_listener.h"
 #include "ui/gl/android/surface_texture.h"
@@ -43,10 +43,15 @@
  private:
   StreamTexture(GpuChannel* channel,
                 int32_t route_id,
-                std::unique_ptr<gles2::AbstractTexture> surface_owner_texture,
                 scoped_refptr<SharedContextState> context_state);
   ~StreamTexture() override;
 
+  // Static function which is used to access |weak_stream_texture| on correct
+  // thread since WeakPtr is not thread safe.
+  static void RunCallback(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      base::WeakPtr<StreamTexture> weak_stream_texture);
+
   // gl::GLImage implementation:
   gfx::Size GetSize() override;
   unsigned GetInternalFormat() override;
@@ -98,13 +103,8 @@
                            uint32_t release_id);
   void OnDestroy();
 
-  // An AbstractTexture which owns |surface_owner_texture_id_|, which is used
-  // by |surface_owner_|.
-  std::unique_ptr<gles2::AbstractTexture> surface_owner_texture_;
-  uint32_t surface_owner_texture_id_;
-
-  // The SurfaceOwner which receives frames.
-  std::unique_ptr<SurfaceOwner> surface_owner_;
+  // The TextureOwner which receives frames.
+  scoped_refptr<TextureOwner> texture_owner_;
 
   // Current transform matrix of the surface owner.
   float current_matrix_[16];
diff --git a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json b/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
index 89a3dacb..e6a6379 100644
--- a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
@@ -3,7 +3,7 @@
     "Run tests on iOS12beta track on 64-bit iOS 12 simulators.",
     "Note: Xcode 11 requires OSX 10.14.3 hence 'host os'"
   ],
-  "xcode build version": "10e1001",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -14,213 +14,5 @@
     "use_goma=true"
   ],
   "tests": [
-    {
-      "include": "common_tests.json",
-      "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_cq_tests.json",
-      "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_cq_tests.json",
-      "device type": "iPhone 6 Plus",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_cq_tests.json",
-      "device type": "iPhone 5s",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_cq_tests.json",
-      "device type": "iPad Pro (12.9-inch)",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_tests.json",
-      "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_tests.json",
-      "device type": "iPhone 6 Plus",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_tests.json",
-      "device type": "iPad Air",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "eg_tests.json",
-      "device type": "iPhone 5s",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "screen_size_dependent_tests.json",
-      "device type": "iPhone 6s Plus",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "screen_size_dependent_tests.json",
-      "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "screen_size_dependent_tests.json",
-      "device type": "iPhone 5s",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    },
-    {
-      "include": "screen_size_dependent_tests.json",
-      "device type": "iPad Air 2",
-      "os": "12.2",
-      "xcode build version": "10e1001",
-      "host os": "Mac-10.14.4",
-      "pool":"Chrome",
-      "optional_dimensions": {
-          "60": [{
-            "host os": "Mac-10.14.5"
-          }],
-          "120": [{
-            "host os": "Mac-10.14.3"
-          }]
-      }
-    }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios13-beta-simulator.json b/ios/build/bots/chromium.fyi/ios13-beta-simulator.json
index 7faf9da9..76f015f 100644
--- a/ios/build/bots/chromium.fyi/ios13-beta-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios13-beta-simulator.json
@@ -3,7 +3,7 @@
     "Run tests on iOS13beta track on 64-bit iOS 13 simulators.",
     "Note: Xcode 11 requires OSX 10.14.4 and up"
   ],
-  "xcode build version": "10e1001",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -49,8 +49,8 @@
       "xcode parallelization": true,
       "include": "eg2_tests.json",
       "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
+      "os": "12.1",
+      "xcode build version": "11m382q",
       "pool":"Chrome",
       "host os": "Mac-10.14.4",
       "optional_dimensions": {
@@ -63,8 +63,8 @@
       "xcode parallelization": true,
       "include": "eg2_tests.json",
       "device type": "iPad (6th generation)",
-      "os": "12.2",
-      "xcode build version": "10e1001",
+      "os": "12.1",
+      "xcode build version": "11m382q",
       "pool":"Chrome",
       "host os": "Mac-10.14.4",
       "optional_dimensions": {
diff --git a/ios/build/bots/chromium.mac/ios13-beta-simulator.json b/ios/build/bots/chromium.mac/ios13-beta-simulator.json
index 268fdb2d..7bbe5c3 100644
--- a/ios/build/bots/chromium.mac/ios13-beta-simulator.json
+++ b/ios/build/bots/chromium.mac/ios13-beta-simulator.json
@@ -5,7 +5,7 @@
     "Note: This file exists only to support the trybot.",
     "It should be kept in sync with the CI configuration in ../chromium.fyi/."
   ],
-  "xcode build version": "10e1001",
+  "xcode build version": "11m382q",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -51,8 +51,8 @@
       "xcode parallelization": true,
       "include": "eg2_tests.json",
       "device type": "iPhone X",
-      "os": "12.2",
-      "xcode build version": "10e1001",
+      "os": "12.1",
+      "xcode build version": "11m382q",
       "pool":"Chrome",
       "host os": "Mac-10.14.4",
       "optional_dimensions": {
@@ -65,8 +65,8 @@
       "xcode parallelization": true,
       "include": "eg2_tests.json",
       "device type": "iPad (6th generation)",
-      "os": "12.2",
-      "xcode build version": "10e1001",
+      "os": "12.1",
+      "xcode build version": "11m382q",
       "pool":"Chrome",
       "host os": "Mac-10.14.4",
       "optional_dimensions": {
diff --git a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm
index bc64993d..6407cb1 100644
--- a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm
+++ b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm
@@ -7,6 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/system/sys_info.h"
@@ -26,11 +27,6 @@
 
 namespace {
 
-// Percentage of battery level which is assumed low enough to have possibly
-// been the reason for the previous session ending in an unclean shutdown.
-// Percent rpresented by a value between 0 and 1.
-const float kCriticallyLowBatteryLevel = 0.01;
-
 // Amount of storage, in kilobytes, considered to be critical enough to
 // negatively effect device operation.
 const int kCriticallyLowDeviceStorage = 1024 * 5;
@@ -170,17 +166,19 @@
   LogLowPowerMode(session_info.deviceWasInLowPowerMode);
   LogDeviceThermalState(session_info.deviceThermalState);
 
+  base::UmaHistogramBoolean("Stability.iOS.UTE.OSRestartedAfterPreviousSession",
+                            session_info.OSRestartedAfterPreviousSession);
+
   bool possible_explanation =
       // Log any of the following cases as a possible explanation for the
       // crash:
-      // - battery is critically low
-      (session_info.deviceBatteryState == DeviceBatteryState::kUnplugged &&
-       session_info.deviceBatteryLevel <= kCriticallyLowBatteryLevel) ||
-      // - storage is extremely low
+      // - storage was critically low
       (session_info.availableDeviceStorage >= 0 &&
        session_info.availableDeviceStorage <= kCriticallyLowDeviceStorage) ||
       // - OS version changed
       session_info.isFirstSessionAfterOSUpgrade ||
+      // - OS was restarted
+      session_info.OSRestartedAfterPreviousSession ||
       // - low power mode enabled
       session_info.deviceWasInLowPowerMode ||
       // - device in abnormal thermal state
diff --git a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider_unittest.mm b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider_unittest.mm
index c96a5f1..328ba38 100644
--- a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider_unittest.mm
+++ b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider_unittest.mm
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+#import <Foundation/Foundation.h>
+
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -17,6 +19,8 @@
 #include "components/metrics/test_enabled_state_provider.h"
 #include "components/metrics/test_metrics_service_client.h"
 #include "components/prefs/testing_pref_service.h"
+#import "ios/chrome/browser/metrics/previous_session_info.h"
+#import "ios/chrome/browser/metrics/previous_session_info_private.h"
 #include "testing/gtest/include/gtest/gtest-param-test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -57,10 +61,10 @@
   bool LastSessionEndedFrozen() override { return was_last_shutdown_frozen_; }
 
  private:
-  bool is_first_launch_after_upgrade_;
-  bool has_crash_logs_;
-  bool received_memory_warning_before_last_shutdown_;
-  bool was_last_shutdown_frozen_;
+  bool is_first_launch_after_upgrade_ = false;
+  bool has_crash_logs_ = false;
+  bool received_memory_warning_before_last_shutdown_ = false;
+  bool was_last_shutdown_frozen_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(MobileSessionShutdownMetricsProviderForTesting);
 };
@@ -173,6 +177,51 @@
   metrics_provider_->ProvidePreviousSessionData(nullptr);
   histogram_tester.ExpectUniqueSample("Stability.MobileSessionShutdownType",
                                       expected_buckets[GetParam()], 1);
+  [PreviousSessionInfo resetSharedInstanceForTesting];
+}
+
+// Tests logging the following metrics:
+//   - Stability.iOS.UTE.HasPossibleExplanation
+//   - Stability.iOS.UTE.OSRestartedAfterPreviousSession
+TEST_F(MobileSessionShutdownMetricsProviderTest,
+       ProvideHasPossibleExplanationMetric) {
+  // Setup the MetricsService and HistogramTester.
+  local_state_.SetBoolean(metrics::prefs::kStabilityExitedCleanly, false);
+  metrics_state_ = metrics::MetricsStateManager::Create(
+      &local_state_, new metrics::TestEnabledStateProvider(false, false),
+      base::string16(), metrics::MetricsStateManager::StoreClientInfoCallback(),
+      metrics::MetricsStateManager::LoadClientInfoCallback());
+  metrics_service_.reset(new metrics::MetricsService(
+      metrics_state_.get(), &metrics_client_, &local_state_));
+  metrics_provider_.reset(new MobileSessionShutdownMetricsProviderForTesting(
+      metrics_service_.get()));
+
+  // Test UTE with no possible explanation.
+  auto histogram_tester = std::make_unique<base::HistogramTester>();
+  [PreviousSessionInfo sharedInstance].OSRestartedAfterPreviousSession = NO;
+  metrics_provider_->ProvidePreviousSessionData(nullptr);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.OSRestartedAfterPreviousSession", false, 1);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.HasPossibleExplanation", false, 1);
+
+  // Test UTE with low battery when OS did not restart.
+  [PreviousSessionInfo sharedInstance].deviceBatteryLevel = 0.01;
+  histogram_tester = std::make_unique<base::HistogramTester>();
+  metrics_provider_->ProvidePreviousSessionData(nullptr);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.OSRestartedAfterPreviousSession", false, 1);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.HasPossibleExplanation", false, 1);
+
+  // Test UTE with low battery when OS restarted after previous session.
+  [PreviousSessionInfo sharedInstance].OSRestartedAfterPreviousSession = YES;
+  histogram_tester = std::make_unique<base::HistogramTester>();
+  metrics_provider_->ProvidePreviousSessionData(nullptr);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.OSRestartedAfterPreviousSession", true, 1);
+  histogram_tester->ExpectUniqueSample(
+      "Stability.iOS.UTE.HasPossibleExplanation", true, 1);
 }
 
 INSTANTIATE_TEST_SUITE_P(/* No InstantiationName */,
diff --git a/ios/chrome/browser/metrics/previous_session_info.h b/ios/chrome/browser/metrics/previous_session_info.h
index 773fcf5..316c588 100644
--- a/ios/chrome/browser/metrics/previous_session_info.h
+++ b/ios/chrome/browser/metrics/previous_session_info.h
@@ -10,6 +10,8 @@
 namespace previous_session_info_constants {
 // Key in the UserDefaults for a boolean value keeping track of memory warnings.
 extern NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating;
+// Key in the UserDefaults for a double value which stores OS start time.
+extern NSString* const kOSStartTime;
 
 // The values of this enum are persisted (both to NSUserDefaults and logs) and
 // represent the state of the last session (which may have been running a
@@ -80,6 +82,10 @@
 // session.
 @property(nonatomic, assign, readonly) BOOL isFirstSessionAfterLanguageChange;
 
+// Whether or not the OS was restarted between the previous and the current
+// session.
+@property(nonatomic, assign, readonly) BOOL OSRestartedAfterPreviousSession;
+
 // The OS version during the previous session or nil if no previous session data
 // is available.
 @property(nonatomic, strong, readonly) NSString* OSVersion;
diff --git a/ios/chrome/browser/metrics/previous_session_info.mm b/ios/chrome/browser/metrics/previous_session_info.mm
index aed0962..892e748 100644
--- a/ios/chrome/browser/metrics/previous_session_info.mm
+++ b/ios/chrome/browser/metrics/previous_session_info.mm
@@ -21,6 +21,12 @@
 
 namespace {
 
+// Returns timestamp (in seconds since January 2001) when OS has started.
+NSTimeInterval GetOSStartTimeIntervalSinceReferenceDate() {
+  return NSDate.timeIntervalSinceReferenceDate -
+         NSProcessInfo.processInfo.systemUptime;
+}
+
 // Translates a UIDeviceBatteryState value to DeviceBatteryState value.
 DeviceBatteryState GetBatteryStateFromUIDeviceBatteryState(
     UIDeviceBatteryState device_battery_state) {
@@ -87,6 +93,7 @@
 namespace previous_session_info_constants {
 NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating =
     @"DidSeeMemoryWarning";
+NSString* const kOSStartTime = @"OSStartTime";
 }  // namespace previous_session_info_constants
 
 @interface PreviousSessionInfo ()
@@ -104,6 +111,7 @@
 @property(nonatomic, assign) BOOL isFirstSessionAfterOSUpgrade;
 @property(nonatomic, assign) BOOL isFirstSessionAfterUpgrade;
 @property(nonatomic, assign) BOOL isFirstSessionAfterLanguageChange;
+@property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
 @property(nonatomic, strong) NSString* OSVersion;
 @property(nonatomic, strong) NSDate* sessionEndTime;
 
@@ -172,6 +180,16 @@
     gSharedInstance.isFirstSessionAfterUpgrade =
         ![lastRanVersion isEqualToString:currentVersion];
 
+    NSTimeInterval lastSystemStartTime =
+        [defaults doubleForKey:previous_session_info_constants::kOSStartTime];
+
+    gSharedInstance.OSRestartedAfterPreviousSession =
+        // Allow 5 seconds variation to account for rounding error.
+        (abs(lastSystemStartTime - GetOSStartTimeIntervalSinceReferenceDate()) >
+         5) &&
+        // Ensure that previous session actually exists.
+        lastSystemStartTime;
+
     NSString* lastRanLanguage = [defaults stringForKey:kLastRanLanguage];
     NSString* currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
     gSharedInstance.isFirstSessionAfterLanguageChange =
@@ -196,6 +214,10 @@
       base::SysUTF8ToNSString(version_info::GetVersionNumber());
   [defaults setObject:currentVersion forKey:kLastRanVersion];
 
+  // Set the current OS start time.
+  [defaults setDouble:GetOSStartTimeIntervalSinceReferenceDate()
+               forKey:previous_session_info_constants::kOSStartTime];
+
   // Set the current OS version.
   NSString* currentOSVersion =
       base::SysUTF8ToNSString(base::SysInfo::OperatingSystemVersion());
diff --git a/ios/chrome/browser/metrics/previous_session_info_private.h b/ios/chrome/browser/metrics/previous_session_info_private.h
index 954c20c3..3c94d04 100644
--- a/ios/chrome/browser/metrics/previous_session_info_private.h
+++ b/ios/chrome/browser/metrics/previous_session_info_private.h
@@ -9,9 +9,9 @@
 
 // Redefined to be read-write.
 @property(nonatomic, assign) BOOL didSeeMemoryWarningShortlyBeforeTerminating;
-
-// Redefined to be read-write.
 @property(nonatomic, assign) BOOL isFirstSessionAfterUpgrade;
+@property(nonatomic, assign) float deviceBatteryLevel;
+@property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
 
 + (void)resetSharedInstanceForTesting;
 
diff --git a/ios/chrome/browser/metrics/previous_session_info_unittest.mm b/ios/chrome/browser/metrics/previous_session_info_unittest.mm
index 2bdbf4fa..b8c9e07 100644
--- a/ios/chrome/browser/metrics/previous_session_info_unittest.mm
+++ b/ios/chrome/browser/metrics/previous_session_info_unittest.mm
@@ -157,6 +157,52 @@
   EXPECT_TRUE([sharedInstance isFirstSessionAfterUpgrade]);
 }
 
+// Creates conditions that exist on the first app run and tests
+// OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationWithoutSystemStartTime) {
+  [PreviousSessionInfo resetSharedInstanceForTesting];
+  [[NSUserDefaults standardUserDefaults]
+      removeObjectForKey:previous_session_info_constants::kOSStartTime];
+
+  EXPECT_FALSE(
+      [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
+// Creates conditions that exist when OS was restarted after the previous app
+// run and tests OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationAfterOSRestart) {
+  [PreviousSessionInfo resetSharedInstanceForTesting];
+
+  // For the previous session OS started 60 seconds before OS has started for
+  // this session.
+  NSTimeInterval current_system_start_time =
+      NSDate.timeIntervalSinceReferenceDate -
+      NSProcessInfo.processInfo.systemUptime;
+  [[NSUserDefaults standardUserDefaults]
+      setDouble:current_system_start_time - 60
+         forKey:previous_session_info_constants::kOSStartTime];
+
+  EXPECT_TRUE(
+      [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
+// Creates conditions that exist when OS was not restarted after the previous
+// app run and tests OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationForSecondSessionAfterOSRestart) {
+  [PreviousSessionInfo resetSharedInstanceForTesting];
+
+  // OS startup time is the same for this and previous session.
+  NSTimeInterval current_system_start_time =
+      NSDate.timeIntervalSinceReferenceDate -
+      NSProcessInfo.processInfo.systemUptime;
+  [[NSUserDefaults standardUserDefaults]
+      setDouble:current_system_start_time
+         forKey:previous_session_info_constants::kOSStartTime];
+
+  EXPECT_FALSE(
+      [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
 TEST_F(PreviousSessionInfoTest, BeginRecordingCurrentSession) {
   [PreviousSessionInfo resetSharedInstanceForTesting];
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index a210f63..a5cabcf 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -526,9 +526,6 @@
 @property(nonatomic, assign, getter=isDismissingModal) BOOL dismissingModal;
 // Whether web usage is enabled for the WebStates in |self.tabModel|.
 @property(nonatomic, assign, getter=isWebUsageEnabled) BOOL webUsageEnabled;
-// Returns YES if the toolbar has not been scrolled out by fullscreen.
-@property(nonatomic, assign, readonly, getter=isToolbarOnScreen)
-    BOOL toolbarOnScreen;
 // Whether a new tab animation is occurring.
 @property(nonatomic, assign, getter=isInNewTabAnimation) BOOL inNewTabAnimation;
 // Whether BVC prefers to hide the status bar. This value is used to determine
@@ -956,8 +953,6 @@
           _browserState);
   ChromeBroadcaster* broadcaster = fullscreenController->broadcaster();
   if (_broadcasting) {
-    fullscreenController->SetWebStateList(self.tabModel.webStateList);
-
     _toolbarUIUpdater = [[LegacyToolbarUIUpdater alloc]
         initWithToolbarUI:[[ToolbarUIState alloc] init]
              toolbarOwner:self
@@ -972,6 +967,8 @@
            webStateList:self.tabModel.webStateList];
     StartBroadcastingMainContentUI(self, broadcaster);
 
+    fullscreenController->SetWebStateList(self.tabModel.webStateList);
+
     _fullscreenUIUpdater = std::make_unique<FullscreenUIUpdater>(self);
     fullscreenController->AddObserver(_fullscreenUIUpdater.get());
     [self updateForFullscreenProgress:fullscreenController->GetProgress()];
@@ -1006,10 +1003,6 @@
       ->SetWebUsageEnabled(webUsageEnabled);
 }
 
-- (BOOL)isToolbarOnScreen {
-  return [self nonFullscreenToolbarHeight] - [self currentHeaderOffset] > 0;
-}
-
 - (void)setInNewTabAnimation:(BOOL)inNewTabAnimation {
   if (_inNewTabAnimation == inNewTabAnimation)
     return;
@@ -3748,22 +3741,12 @@
 #pragma mark - ToolbarHeightProviderForFullscreen
 
 - (CGFloat)collapsedTopToolbarHeight {
-  if (IsVisibleURLNewTabPage(self.currentWebState) && ![self canShowTabStrip]) {
-    // When the NTP is displayed in a horizontally compact environment, the top
-    // toolbars are hidden.
-    return 0;
-  }
   return self.view.safeAreaInsets.top +
          ToolbarCollapsedHeight(
              self.traitCollection.preferredContentSizeCategory);
 }
 
 - (CGFloat)expandedTopToolbarHeight {
-  if (IsVisibleURLNewTabPage(self.currentWebState) && ![self canShowTabStrip]) {
-    // When the NTP is displayed in a horizontally compact environment, the top
-    // toolbars are hidden.
-    return 0;
-  }
   return [self primaryToolbarHeightWithInset] +
          ([self canShowTabStrip] ? self.tabStripView.frame.size.height : 0.0) +
          self.headerOffset;
@@ -3773,13 +3756,6 @@
   return [self secondaryToolbarHeightWithInset];
 }
 
-#pragma mark - Toolbar height helpers
-
-- (CGFloat)nonFullscreenToolbarHeight {
-  return MAX(
-      0, [self expandedTopToolbarHeight] - [self collapsedTopToolbarHeight]);
-}
-
 #pragma mark - FullscreenUIElement methods
 
 - (void)updateForFullscreenProgress:(CGFloat)progress {
@@ -3831,12 +3807,22 @@
 
 #pragma mark - FullscreenUIElement helpers
 
+// Returns the height difference between the fully expanded and fully collapsed
+// primary toolbar.
+- (CGFloat)primaryToolbarHeightDelta {
+  FullscreenController* controller =
+      FullscreenControllerFactory::GetForBrowserState(self.browserState);
+  CGFloat fullyExpandedHeight = controller->GetMaxViewportInsets().top;
+  CGFloat fullyCollapsedHeight = controller->GetMinViewportInsets().top;
+  return std::max(0.0, fullyExpandedHeight - fullyCollapsedHeight);
+}
+
 // Translates the header views up and down according to |progress|, where a
 // progress of 1.0 fully shows the headers and a progress of 0.0 fully hides
 // them.
 - (void)updateHeadersForFullscreenProgress:(CGFloat)progress {
   CGFloat offset =
-      AlignValueToPixel((1.0 - progress) * [self nonFullscreenToolbarHeight]);
+      AlignValueToPixel((1.0 - progress) * [self primaryToolbarHeightDelta]);
   [self setFramesForHeaders:[self headerViews] atOffset:offset];
 }
 
@@ -3887,7 +3873,7 @@
   // returns the height of the toolbar extending below this view controller's
   // safe area, so the unsafe top height must be added.
   CGFloat top = AlignValueToPixel(
-      self.headerHeight + (progress - 1.0) * [self nonFullscreenToolbarHeight]);
+      self.headerHeight + (progress - 1.0) * [self primaryToolbarHeightDelta]);
   // If the bottom toolbar is locked into place, use 1.0 instead of |progress|.
   CGFloat bottomProgress =
       base::FeatureList::IsEnabled(fullscreen::features::kLockBottomToolbar)
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 f56c6b5..b10a070 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
@@ -58,6 +58,12 @@
                            int index,
                            bool user_action) override;
 
+  // Called when |web_state| is activated in |web_state_list_|.
+  void WebStateWasActivated(web::WebState* web_state);
+
+  // Called when |web_state| is removed from |web_state_list_|.
+  void WebStateWasRemoved(web::WebState* web_state);
+
   // Whether |web_state| has been activated during the lifetime of this object.
   bool HasWebStateBeenActivated(web::WebState* web_state);
 
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 58f0d68..97b9aeb 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
@@ -40,7 +40,7 @@
   web_state_list_ = web_state_list;
   if (web_state_list_) {
     web_state_list_->AddObserver(this);
-    web_state_observer_.SetWebState(web_state_list_->GetActiveWebState());
+    WebStateWasActivated(web_state_list_->GetActiveWebState());
   } else {
     web_state_observer_.SetWebState(nullptr);
   }
@@ -73,16 +73,11 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int index) {
-  if (HasWebStateBeenActivated(old_web_state))
-    activated_web_states_.erase(old_web_state);
+  WebStateWasRemoved(old_web_state);
   if (new_web_state == web_state_list->GetActiveWebState()) {
     // Reset the model if the active WebState is replaced.
-    web_state_observer_.SetWebState(new_web_state);
     model_->ResetForNavigation();
-    if (new_web_state) {
-      MoveContentBelowHeader(new_web_state->GetWebViewProxy(), model_);
-      activated_web_states_.insert(new_web_state);
-    }
+    WebStateWasActivated(new_web_state);
   }
 }
 
@@ -92,21 +87,14 @@
     web::WebState* new_web_state,
     int active_index,
     int reason) {
-  web_state_observer_.SetWebState(new_web_state);
-  // If this is the first time the WebState was activated, move its content
-  // below the header.
-  if (new_web_state && !HasWebStateBeenActivated(new_web_state)) {
-    MoveContentBelowHeader(new_web_state->GetWebViewProxy(), model_);
-    activated_web_states_.insert(new_web_state);
-  }
+  WebStateWasActivated(new_web_state);
 }
 
 void FullscreenWebStateListObserver::WebStateDetachedAt(
     WebStateList* web_state_list,
     web::WebState* web_state,
     int index) {
-  if (HasWebStateBeenActivated(web_state))
-    activated_web_states_.erase(web_state);
+  WebStateWasRemoved(web_state);
 }
 
 void FullscreenWebStateListObserver::WillCloseWebStateAt(
@@ -114,6 +102,20 @@
     web::WebState* web_state,
     int index,
     bool user_action) {
+  WebStateWasRemoved(web_state);
+}
+
+void FullscreenWebStateListObserver::WebStateWasActivated(
+    web::WebState* web_state) {
+  web_state_observer_.SetWebState(web_state);
+  if (web_state && !HasWebStateBeenActivated(web_state)) {
+    MoveContentBelowHeader(web_state->GetWebViewProxy(), model_);
+    activated_web_states_.insert(web_state);
+  }
+}
+
+void FullscreenWebStateListObserver::WebStateWasRemoved(
+    web::WebState* web_state) {
   if (HasWebStateBeenActivated(web_state))
     activated_web_states_.erase(web_state);
 }
diff --git a/ios/web/public/test/error_test_util.h b/ios/web/public/test/error_test_util.h
index f84106e..c34e169 100644
--- a/ios/web/public/test/error_test_util.h
+++ b/ios/web/public/test/error_test_util.h
@@ -5,15 +5,30 @@
 #ifndef IOS_WEB_PUBLIC_TEST_ERROR_TEST_UTIL_H_
 #define IOS_WEB_PUBLIC_TEST_ERROR_TEST_UTIL_H_
 
+#include <string>
+
+class GURL;
+
 @class NSError;
 
 namespace web {
+
+class WebState;
+
 namespace testing {
 
 // Creates Chrome specific error from a regular NSError. Returned error has the
 // same format and structure as errors provided in ios/web callbacks.
 NSError* CreateTestNetError(NSError* error);
 
+// Builds the text for an error page in TestWebClient.
+std::string GetErrorText(WebState* web_state,
+                         const GURL& url,
+                         const std::string& error_domain,
+                         long error_code,
+                         bool is_post,
+                         bool is_off_the_record);
+
 }  // namespace testing
 }  // namespace web
 
diff --git a/ios/web/public/test/error_test_util.mm b/ios/web/public/test/error_test_util.mm
index 435578ae..26139c9 100644
--- a/ios/web/public/test/error_test_util.mm
+++ b/ios/web/public/test/error_test_util.mm
@@ -4,7 +4,12 @@
 
 #import "ios/web/public/test/error_test_util.h"
 
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#import "ios/web/public/web_state/web_state.h"
 #import "ios/web/web_view/error_translation_util.h"
+#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -17,5 +22,17 @@
   return NetErrorFromError(error);
 }
 
+std::string GetErrorText(WebState* web_state,
+                         const GURL& url,
+                         const std::string& error_domain,
+                         long error_code,
+                         bool is_post,
+                         bool is_off_the_record) {
+  return base::StringPrintf(
+      "web_state: %p url: %s domain: %s code: %ld post: %d otr: %d", web_state,
+      url.spec().c_str(), error_domain.c_str(), error_code, is_post,
+      is_off_the_record);
+}
+
 }  // namespace testing
 }  // namespace web
diff --git a/ios/web/public/test/fakes/BUILD.gn b/ios/web/public/test/fakes/BUILD.gn
index 431cc072..0c9fd36 100644
--- a/ios/web/public/test/fakes/BUILD.gn
+++ b/ios/web/public/test/fakes/BUILD.gn
@@ -18,6 +18,7 @@
     "//ios/web/public/js_messaging",
     "//ios/web/public/security",
     "//ios/web/public/session",
+    "//ios/web/public/test:util",
     "//ios/web/test:test_constants",
     "//ios/web/web_state/ui:crw_web_view_navigation_proxy",
     "//ios/web/webui:webui",
diff --git a/ios/web/public/test/fakes/test_web_client.h b/ios/web/public/test/fakes/test_web_client.h
index f3d3621..fcd9072 100644
--- a/ios/web/public/test/fakes/test_web_client.h
+++ b/ios/web/public/test/fakes/test_web_client.h
@@ -45,6 +45,12 @@
                              const GURL&,
                              bool overridable,
                              const base::Callback<void(bool)>&) override;
+  void PrepareErrorPage(WebState* web_state,
+                        const GURL& url,
+                        NSError* error,
+                        bool is_post,
+                        bool is_off_the_record,
+                        base::OnceCallback<void(NSString*)> callback) override;
   UIView* GetWindowedContainer() override;
 
   // Sets |plugin_not_supported_text_|.
diff --git a/ios/web/public/test/fakes/test_web_client.mm b/ios/web/public/test/fakes/test_web_client.mm
index 557c62a..e0b7bc3 100644
--- a/ios/web/public/test/fakes/test_web_client.mm
+++ b/ios/web/public/test/fakes/test_web_client.mm
@@ -7,7 +7,10 @@
 #import <UIKit/UIKit.h>
 
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
+#include "ios/web/public/test/error_test_util.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/test/test_url_constants.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -85,6 +88,18 @@
   allow_certificate_errors_ = flag;
 }
 
+void TestWebClient::PrepareErrorPage(
+    WebState* web_state,
+    const GURL& url,
+    NSError* error,
+    bool is_post,
+    bool is_off_the_record,
+    base::OnceCallback<void(NSString*)> callback) {
+  std::move(callback).Run(base::SysUTF8ToNSString(testing::GetErrorText(
+      web_state, url, base::SysNSStringToUTF8(error.domain), error.code,
+      is_post, is_off_the_record)));
+}
+
 UIView* TestWebClient::GetWindowedContainer() {
   return UIApplication.sharedApplication.keyWindow.rootViewController.view;
 }
diff --git a/ios/web/web_state/bad_ssl_response_inttest.mm b/ios/web/web_state/bad_ssl_response_inttest.mm
index 41a8143..92440c4 100644
--- a/ios/web/web_state/bad_ssl_response_inttest.mm
+++ b/ios/web/web_state/bad_ssl_response_inttest.mm
@@ -11,6 +11,7 @@
 #import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #include "ios/web/public/session/session_certificate_policy_cache.h"
+#import "ios/web/public/test/error_test_util.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
 #import "ios/web/public/test/navigation_test_util.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
@@ -32,27 +33,39 @@
 namespace web {
 
 // BadSslResponseTest is parameterized on this enum to test both
-// LegacyNavigationManagerImpl and WKBasedNavigationManagerImpl.
-enum NavigationManagerChoice {
-  TEST_LEGACY_NAVIGATION_MANAGER,
-  TEST_WK_BASED_NAVIGATION_MANAGER,
+// LegacyNavigationManagerImpl and WKBasedNavigationManagerImpl, and both
+// committed and non-committed interstitials.
+typedef NS_ENUM(NSUInteger, TestParam) {
+  EmptyTestParam = 0,
+  EnableSlimNavigationManager = 1 << 0,
+  EnableCommittedInterstitials = 1 << 1,
+  MaxTestParam = 1 << 2,
 };
 
 // Test fixture for loading https pages with self signed certificate.
-class BadSslResponseTest
-    : public WebTestWithWebState,
-      public ::testing::WithParamInterface<NavigationManagerChoice> {
+class BadSslResponseTest : public WebTestWithWebState,
+                           public ::testing::WithParamInterface<TestParam> {
  protected:
   BadSslResponseTest()
       : WebTestWithWebState(std::make_unique<TestWebClient>()),
         https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {
-    if (GetParam() == TEST_LEGACY_NAVIGATION_MANAGER) {
-      scoped_feature_list_.InitAndDisableFeature(
-          features::kSlimNavigationManager);
+    std::vector<base::Feature> enabled;
+    std::vector<base::Feature> disabled;
+
+    if (SlimNavigationManagerEnabled()) {
+      enabled.push_back(features::kSlimNavigationManager);
     } else {
-      scoped_feature_list_.InitAndEnableFeature(
-          features::kSlimNavigationManager);
+      disabled.push_back(features::kSlimNavigationManager);
     }
+
+    if (CommittedInterstitialsEnabled()) {
+      enabled.push_back(features::kSSLCommittedInterstitials);
+    } else {
+      disabled.push_back(features::kSSLCommittedInterstitials);
+    }
+
+    scoped_feature_list_.InitWithFeatures(enabled, disabled);
+
     RegisterDefaultHandlers(&https_server_);
   }
 
@@ -61,6 +74,16 @@
     ASSERT_TRUE(https_server_.Start());
   }
 
+  // Convenience getters for the test params.
+  bool SlimNavigationManagerEnabled() {
+    return (GetParam() & EnableSlimNavigationManager) ==
+           EnableSlimNavigationManager;
+  }
+  bool CommittedInterstitialsEnabled() {
+    return (GetParam() & EnableCommittedInterstitials) ==
+           EnableCommittedInterstitials;
+  }
+
   TestWebClient* web_client() {
     return static_cast<TestWebClient*>(GetWebClient());
   }
@@ -74,6 +97,9 @@
 // via WebClient. Test verifies the arguments passed to
 // WebClient::AllowCertificateError.
 TEST_P(BadSslResponseTest, RejectLoad) {
+  if (CommittedInterstitialsEnabled()) {
+    return;
+  }
   web_client()->SetAllowCertificateErrors(false);
   const GURL url = https_server_.GetURL("/");
   test::LoadUrl(web_state(), url);
@@ -97,6 +123,9 @@
 // Tests navigation to a page with self signed SSL cert and allowing the load
 // via WebClient.
 TEST_P(BadSslResponseTest, AllowLoad) {
+  if (CommittedInterstitialsEnabled()) {
+    return;
+  }
   web_client()->SetAllowCertificateErrors(true);
   GURL url(https_server_.GetURL("/echo"));
   test::LoadUrl(web_state(), url);
@@ -157,6 +186,9 @@
 // Tests creating WebState with CRWSessionCertificateStorage and populating
 // CertificatePolicyCache.
 TEST_P(BadSslResponseTest, ReadFromSessionCertificateStorage) {
+  if (CommittedInterstitialsEnabled()) {
+    return;
+  }
   // Create WebState with CRWSessionCertificateStorage.
   GURL url(https_server_.GetURL("/echo"));
   scoped_refptr<net::X509Certificate> cert = https_server_.GetCertificate();
@@ -189,11 +221,34 @@
   EXPECT_EQ(url, web_state->GetLastCommittedURL());
 }
 
+// Tests that an error page is shown for SSL cert errors when committed
+// interstitials are enabled.
+TEST_P(BadSslResponseTest, ShowSSLErrorPageCommittedInterstitial) {
+  if (!CommittedInterstitialsEnabled()) {
+    return;
+  }
+  web_client()->SetAllowCertificateErrors(false);
+  const GURL url = https_server_.GetURL("/");
+  test::LoadUrl(web_state(), url);
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
+    base::RunLoop().RunUntilIdle();
+    return !web_state()->IsLoading();
+  }));
+  ASSERT_TRUE(test::WaitForWebViewContainingText(
+      web_state(),
+      testing::GetErrorText(web_state(), url, "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorServerCertificateUntrusted,
+                            /*is_post=*/false, /*is_otr=*/false)));
+}
+
 // Tests navigation to a page with self signed SSL cert and allowing the load
 // via WebClient. Subsequent navigation should not call AllowCertificateError
 // but always allow the load.
 // TODO(crbug.com/973635): fix and reenable this test.
 TEST_P(BadSslResponseTest, DISABLED_RememberCertDecision) {
+  if (CommittedInterstitialsEnabled()) {
+    return;
+  }
   // Allow the load via WebClient.
   web_client()->SetAllowCertificateErrors(true);
   GURL url(https_server_.GetURL("/echo"));
@@ -209,11 +264,8 @@
   EXPECT_EQ(url2, web_state()->GetLastCommittedURL());
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ProgrammaticBadSslResponseTest,
-    BadSslResponseTest,
-    ::testing::Values(
-        NavigationManagerChoice::TEST_LEGACY_NAVIGATION_MANAGER,
-        NavigationManagerChoice::TEST_WK_BASED_NAVIGATION_MANAGER));
+INSTANTIATE_TEST_SUITE_P(,
+                         BadSslResponseTest,
+                         ::testing::Range(EmptyTestParam, MaxTestParam));
 
 }  // namespace web {
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm
index 2c95bfe..ce77308 100644
--- a/ios/web/web_state/error_page_inttest.mm
+++ b/ios/web/web_state/error_page_inttest.mm
@@ -17,7 +17,9 @@
 #include "ios/web/public/security/security_style.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "ios/web/public/test/element_selector.h"
+#import "ios/web/public/test/error_test_util.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
+#import "ios/web/public/test/fakes/test_web_client.h"
 #include "ios/web/public/test/fakes/test_web_state_observer.h"
 #import "ios/web/public/test/navigation_test_util.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
@@ -38,42 +40,16 @@
 
 namespace {
 
-// Builds the text for the error page in TestWebClient.
-std::string GetErrorText(WebState* web_state,
-                         const GURL& url,
-                         const std::string& error_domain,
-                         long error_code,
-                         bool is_post,
-                         bool is_off_the_record) {
-  return base::StringPrintf(
-      "web_state: %p url: %s domain: %s code: %ld post: %d otr: %d", web_state,
-      url.spec().c_str(), error_domain.c_str(), error_code, is_post,
-      is_off_the_record);
-}
-
 // Waits for text for and error in NSURLErrorDomain and
 // kCFURLErrorNetworkConnectionLost error code.
 bool WaitForErrorText(WebState* web_state, const GURL& url) WARN_UNUSED_RESULT;
 bool WaitForErrorText(WebState* web_state, const GURL& url) {
   return test::WaitForWebViewContainingText(
       web_state,
-      GetErrorText(web_state, url, "NSURLErrorDomain", /*error_code*/ -1005,
-                   /*is_post*/ false, /*is_otr*/ false));
+      testing::GetErrorText(web_state, url, "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorNetworkConnectionLost,
+                            /*is_post=*/false, /*is_otr=*/false));
 }
-
-// Overrides PrepareErrorPage to render all important arguments.
-class TestWebClient : public WebClient {
-  void PrepareErrorPage(WebState* web_state,
-                        const GURL& url,
-                        NSError* error,
-                        bool is_post,
-                        bool is_off_the_record,
-                        base::OnceCallback<void(NSString*)> callback) override {
-    std::move(callback).Run(base::SysUTF8ToNSString(
-        GetErrorText(web_state, url, base::SysNSStringToUTF8(error.domain),
-                     error.code, is_post, is_off_the_record)));
-  }
-};
 }  // namespace
 
 // ErrorPageTest is parameterized on this enum to test both
@@ -94,14 +70,14 @@
     RegisterDefaultHandlers(&server_);
     server_.RegisterRequestHandler(base::BindRepeating(
         &net::test_server::HandlePrefixedRequest, "/echo-query",
-        base::BindRepeating(&testing::HandleEchoQueryOrCloseSocket,
+        base::BindRepeating(::testing::HandleEchoQueryOrCloseSocket,
                             std::cref(server_responds_with_content_))));
     server_.RegisterRequestHandler(
         base::BindRepeating(&net::test_server::HandlePrefixedRequest, "/iframe",
-                            base::BindRepeating(&testing::HandleIFrame)));
+                            base::BindRepeating(::testing::HandleIFrame)));
     server_.RegisterRequestHandler(
         base::BindRepeating(&net::test_server::HandlePrefixedRequest, "/form",
-                            base::BindRepeating(&testing::HandleForm)));
+                            base::BindRepeating(::testing::HandleForm)));
 
     if (GetParam() == NavigationManagerChoice::LEGACY) {
       scoped_feature_list_.InitAndDisableFeature(
@@ -190,7 +166,7 @@
 
 // Loads the URL which fails to load, then sucessfully reloads the page.
 TEST_P(ErrorPageTest, ReloadErrorPage) {
-  // No response leads to -1005 error code.
+  // No response leads to -1005 error code (NSURLErrorNetworkConnectionLost).
   server_responds_with_content_ = false;
   test::LoadUrl(web_state(), server_.GetURL("/echo-query?foo"));
   ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/echo-query?foo")));
@@ -210,7 +186,8 @@
   test::LoadUrl(web_state(), server_.GetURL("/echo-query?foo"));
   ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "foo"));
 
-  // Reload the page, no response leads to -1005 error code.
+  // Reload the page, no response leads to -1005 error code
+  // (NSURLErrorNetworkConnectionLost).
   server_responds_with_content_ = false;
   web_state()->GetNavigationManager()->Reload(ReloadType::NORMAL,
                                               /*check_for_repost=*/false);
@@ -314,7 +291,7 @@
 
 // Loads the URL which redirects to unresponsive server.
 TEST_P(ErrorPageTest, RedirectToFailingURL) {
-  // No response leads to -1005 error code.
+  // No response leads to -1005 error code (NSURLErrorNetworkConnectionLost).
   server_responds_with_content_ = false;
   test::LoadUrl(web_state(), server_.GetURL("/server-redirect?echo-query"));
   // Error is displayed after the resdirection to /echo-query.
@@ -339,7 +316,7 @@
   WebState::CreateParams params(&browser_state);
   auto web_state = WebState::Create(params);
 
-  // No response leads to -1005 error code.
+  // No response leads to -1005 error code (NSURLErrorNetworkConnectionLost).
   server_responds_with_content_ = false;
   test::LoadUrl(web_state.get(), server_.GetURL("/echo-query?foo"));
   // LoadIfNecessary is needed because the view is not created (but needed) when
@@ -347,25 +324,28 @@
   web_state->GetNavigationManager()->LoadIfNecessary();
   ASSERT_TRUE(test::WaitForWebViewContainingText(
       web_state.get(),
-      GetErrorText(web_state.get(), server_.GetURL("/echo-query?foo"),
-                   "NSURLErrorDomain", /*error_code*/ -1005,
-                   /*is_post*/ false, /*is_otr*/ true)));
+      testing::GetErrorText(web_state.get(), server_.GetURL("/echo-query?foo"),
+                            "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorNetworkConnectionLost,
+                            /*is_post=*/false, /*is_otr=*/true)));
 }
 
 // Loads the URL with form which fails to submit.
 TEST_P(ErrorPageTest, FormSubmissionError) {
   test::LoadUrl(web_state(), server_.GetURL("/form?close-socket"));
-  ASSERT_TRUE(
-      test::WaitForWebViewContainingText(web_state(), testing::kTestFormPage));
+  ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(),
+                                                 ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
   ExecuteJavaScript(@"document.getElementById('form').submit();");
 
   // Error is displayed after the form submission navigation.
   ASSERT_TRUE(test::WaitForWebViewContainingText(
-      web_state(), GetErrorText(web_state(), server_.GetURL("/close-socket"),
-                                "NSURLErrorDomain", /*error_code*/ -1005,
-                                /*is_post*/ true, /*is_otr*/ false)));
+      web_state(),
+      testing::GetErrorText(web_state(), server_.GetURL("/close-socket"),
+                            "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorNetworkConnectionLost,
+                            /*is_post=*/true, /*is_otr=*/false)));
 }
 
 // Loads an item and checks that virtualURL and URL after displaying the error
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm
index d0b526db..c547752 100644
--- a/ios/web/web_state/web_state_observer_inttest.mm
+++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -28,6 +28,7 @@
 #import "ios/web/public/navigation/web_state_policy_decider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
+#import "ios/web/public/test/error_test_util.h"
 #include "ios/web/public/test/fakes/test_web_state_observer.h"
 #import "ios/web/public/test/navigation_test_util.h"
 #import "ios/web/public/test/web_view_content_test_util.h"
@@ -842,9 +843,9 @@
 }  // namespace
 
 using net::test_server::EmbeddedTestServer;
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
+using ::testing::Return;
+using ::testing::StrictMock;
+using ::testing::_;
 using base::test::ios::kWaitForPageLoadTimeout;
 using base::test::ios::WaitUntilConditionOrTimeout;
 using test::WaitForWebViewContainingText;
@@ -882,10 +883,10 @@
     test_server_ = std::make_unique<EmbeddedTestServer>();
     test_server_->RegisterRequestHandler(
         base::BindRepeating(&net::test_server::HandlePrefixedRequest, "/form",
-                            base::BindRepeating(&testing::HandleForm)));
+                            base::BindRepeating(::testing::HandleForm)));
     test_server_->RegisterRequestHandler(base::BindRepeating(
         &net::test_server::HandlePrefixedRequest, "/download",
-        base::BindRepeating(&testing::HandleDownload)));
+        base::BindRepeating(::testing::HandleDownload)));
     RegisterDefaultHandlers(test_server_.get());
     test_server_->ServeFilesFromSourceDirectory(
         base::FilePath("ios/testing/data/http_server_files/"));
@@ -907,7 +908,7 @@
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   ScopedObserver<WebState, WebStateObserver> scoped_observer_;
-  testing::InSequence callbacks_sequence_checker_;
+  ::testing::InSequence callbacks_sequence_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(WebStateObserverTest);
 };
@@ -1079,7 +1080,9 @@
   web::NavigationItem* item = manager->GetPendingItem();
   item->SetTitle(base::UTF8ToUTF16(kFailedTitle));
   ASSERT_TRUE(test::WaitForWebViewContainingText(
-      web_state(), "The network connection was lost."));
+      web_state(), testing::GetErrorText(web_state(), url, "NSURLErrorDomain",
+                                         /*error_code=*/-1005,
+                                         /*is_post=*/false, /*is_otr=*/false)));
   DCHECK_EQ(item->GetTitle(), base::UTF8ToUTF16(kFailedTitle));
 }
 
@@ -1779,7 +1782,7 @@
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ASSERT_TRUE(LoadUrl(url));
   ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormPage));
+      WaitForWebViewContainingText(web_state(), ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
   NavigationContext* context = nullptr;
@@ -1812,8 +1815,8 @@
   EXPECT_CALL(observer_,
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ExecuteJavaScript(@"document.getElementById('form').submit();");
-  ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormFieldValue));
+  ASSERT_TRUE(WaitForWebViewContainingText(web_state(),
+                                           ::testing::kTestFormFieldValue));
 }
 
 // Tests successful reload of a page returned for post request.
@@ -1840,7 +1843,7 @@
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ASSERT_TRUE(LoadUrl(url));
   ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormPage));
+      WaitForWebViewContainingText(web_state(), ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
   WebStatePolicyDecider::RequestInfo form_request_info(
@@ -1865,8 +1868,8 @@
   EXPECT_CALL(observer_,
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ExecuteJavaScript(@"window.document.getElementById('form').submit();");
-  ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormFieldValue));
+  ASSERT_TRUE(WaitForWebViewContainingText(web_state(),
+                                           ::testing::kTestFormFieldValue));
 
   // Reload the page.
   NavigationContext* context = nullptr;
@@ -1937,7 +1940,7 @@
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ASSERT_TRUE(LoadUrl(url));
   ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormPage));
+      WaitForWebViewContainingText(web_state(), ::testing::kTestFormPage));
 
   // Submit the form using JavaScript.
   WebStatePolicyDecider::RequestInfo form_request_info(
@@ -1960,8 +1963,8 @@
   EXPECT_CALL(observer_,
               PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS));
   ExecuteJavaScript(@"window.document.getElementById('form').submit();");
-  ASSERT_TRUE(
-      WaitForWebViewContainingText(web_state(), testing::kTestFormFieldValue));
+  ASSERT_TRUE(WaitForWebViewContainingText(web_state(),
+                                           ::testing::kTestFormFieldValue));
 
   // Go Back.
   WebStatePolicyDecider::RequestInfo back_request_info(
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 999cd1da..02b3453 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -23,6 +23,7 @@
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
+#import "ios/web/public/test/error_test_util.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
 #import "ios/web/public/test/fakes/test_web_state_delegate.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
@@ -47,9 +48,6 @@
 namespace web {
 namespace {
 
-// Error when loading an app specific page.
-const char kUnsupportedUrlErrorPage[] = "NSURLErrorDomain error -1002.";
-
 // A text string from the test HTML page in the session storage returned  by
 // GetTestSessionStorage().
 const char kTestSessionStoragePageText[] = "pony";
@@ -646,9 +644,13 @@
   EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
     return !web_state()->IsLoading();
   }));
-  // Wait for the error loading.
-  EXPECT_TRUE(test::WaitForWebViewContainingText(web_state(),
-                                                 kUnsupportedUrlErrorPage));
+  // Wait for the error loading and check that it corresponds with
+  // kUnsupportedUrlErrorPage.
+  EXPECT_TRUE(test::WaitForWebViewContainingText(
+      web_state(),
+      testing::GetErrorText(web_state(), app_specific_url, "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorUnsupportedURL,
+                            /*is_post=*/false, /*is_otr=*/false)));
   NSString* data_html = @(kTestPageHTML);
   web_state()->LoadData([data_html dataUsingEncoding:NSUTF8StringEncoding],
                         @"text/html", GURL("https://www.chromium.org"));
@@ -657,7 +659,16 @@
 }
 
 // Tests that reloading after loading HTML page will load the online page.
-TEST_P(WebStateTest, LoadChromeThenWaitThenHTMLThenReload) {
+// TODO(crbug.com/994468): This test sometimes shows an error page instead of
+// the online page when SlimNavigationManager is enabled.
+#if !TARGET_IPHONE_SIMULATOR
+#define MAYBE_LoadChromeThenWaitThenHTMLThenReload \
+  LoadChromeThenWaitThenHTMLThenReload
+#else
+#define MAYBE_LoadChromeThenWaitThenHTMLThenReload \
+  FLAKY_LoadChromeThenWaitThenHTMLThenReload
+#endif
+TEST_P(WebStateTest, MAYBE_LoadChromeThenWaitThenHTMLThenReload) {
   net::EmbeddedTestServer server;
   net::test_server::RegisterDefaultHandlers(&server);
   ASSERT_TRUE(server.Start());
@@ -671,8 +682,11 @@
   EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
     return !web_state()->IsLoading();
   }));
-  EXPECT_TRUE(test::WaitForWebViewContainingText(web_state(),
-                                                 kUnsupportedUrlErrorPage));
+  EXPECT_TRUE(test::WaitForWebViewContainingText(
+      web_state(),
+      testing::GetErrorText(web_state(), app_specific_url, "NSURLErrorDomain",
+                            /*error_code=*/NSURLErrorUnsupportedURL,
+                            /*is_post=*/false, /*is_otr=*/false)));
   NSString* data_html = @(kTestPageHTML);
   web_state()->LoadData([data_html dataUsingEncoding:NSUTF8StringEncoding],
                         @"text/html", echo_url);
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 4a7e1557..cba8b53 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -173,6 +173,7 @@
     deps += [
       # The test needs the java dependencies to add the java classes for their
       # native counterparts to the test apk.
+      "//gpu/ipc/common:android_texture_owner_unittests",
       "//media/base/android:media_java",
       "//media/base/android:unit_tests",
       "//media/gpu:android_video_decode_accelerator_unittests",
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 4f6b42c..fbb0ecc2 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -28,6 +28,10 @@
     visibility += [ "//media/base/mac" ]
   }
 
+  if (is_android) {
+    visibility += [ "//gpu/ipc/common:android_texture_owner_unittests" ]
+  }
+
   sources = [
     "android_overlay_config.cc",
     "android_overlay_config.h",
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 15e9fe77..b722fb5 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -117,8 +117,6 @@
       "android/device_info.h",
       "android/direct_shared_image_video_provider.cc",
       "android/direct_shared_image_video_provider.h",
-      "android/image_reader_gl_owner.cc",
-      "android/image_reader_gl_owner.h",
       "android/maybe_render_early_manager.cc",
       "android/maybe_render_early_manager.h",
       "android/media_codec_video_decoder.cc",
@@ -132,10 +130,6 @@
       "android/shared_image_video_provider.h",
       "android/surface_chooser_helper.cc",
       "android/surface_chooser_helper.h",
-      "android/surface_texture_gl_owner.cc",
-      "android/surface_texture_gl_owner.h",
-      "android/texture_owner.cc",
-      "android/texture_owner.h",
       "android/video_frame_factory.h",
       "android/video_frame_factory_impl.cc",
       "android/video_frame_factory_impl.h",
@@ -143,6 +137,7 @@
     libs += [ "android" ]
     deps += [
       "//gpu/ipc/common:android_image_reader_utils",
+      "//gpu/ipc/common:android_texture_owner",
 
       # TODO(crbug.com/789435): This can be removed once CdmManager is removed.
       "//gpu/ipc/common:ipc_common_sources",
@@ -431,6 +426,7 @@
     if (is_android) {
       deps += [
         ":android_video_decode_accelerator_unittests",
+        "//gpu/ipc/common:android_texture_owner_unittests",
         "//media/base/android:media_java",
         "//media/test:run_all_unittests",
         "//ui/android:ui_java",
@@ -468,11 +464,8 @@
       "android/codec_wrapper_unittest.cc",
       "android/fake_codec_allocator.cc",
       "android/fake_codec_allocator.h",
-      "android/image_reader_gl_owner_unittest.cc",
       "android/maybe_render_early_manager_unittest.cc",
       "android/media_codec_video_decoder_unittest.cc",
-      "android/mock_abstract_texture.cc",
-      "android/mock_abstract_texture.h",
       "android/mock_android_video_surface_chooser.cc",
       "android/mock_android_video_surface_chooser.h",
       "android/mock_codec_buffer_wait_coordinator.cc",
@@ -483,11 +476,8 @@
       "android/mock_device_info.h",
       "android/mock_promotion_hint_aggregator.cc",
       "android/mock_promotion_hint_aggregator.h",
-      "android/mock_texture_owner.cc",
-      "android/mock_texture_owner.h",
       "android/promotion_hint_aggregator_impl_unittest.cc",
       "android/surface_chooser_helper_unittest.cc",
-      "android/surface_texture_gl_owner_unittest.cc",
       "android/video_frame_factory_impl_unittest.cc",
     ]
     deps = [
@@ -495,6 +485,7 @@
       ":gpu",
       "//base/test:test_support",
       "//gpu:test_support",
+      "//gpu/ipc/common:android_texture_owner_test_support",
       "//media",
       "//media:test_support",
       "//testing/gmock",
diff --git a/media/gpu/android/codec_buffer_wait_coordinator.cc b/media/gpu/android/codec_buffer_wait_coordinator.cc
index 097b03270..09834d9 100644
--- a/media/gpu/android/codec_buffer_wait_coordinator.cc
+++ b/media/gpu/android/codec_buffer_wait_coordinator.cc
@@ -27,7 +27,7 @@
 };
 
 CodecBufferWaitCoordinator::CodecBufferWaitCoordinator(
-    scoped_refptr<TextureOwner> texture_owner)
+    scoped_refptr<gpu::TextureOwner> texture_owner)
     : texture_owner_(std::move(texture_owner)),
       frame_available_event_(new FrameAvailableEvent()),
       task_runner_(base::ThreadTaskRunnerHandle::Get()) {
diff --git a/media/gpu/android/codec_buffer_wait_coordinator.h b/media/gpu/android/codec_buffer_wait_coordinator.h
index 2f758b4..a06b115 100644
--- a/media/gpu/android/codec_buffer_wait_coordinator.h
+++ b/media/gpu/android/codec_buffer_wait_coordinator.h
@@ -9,7 +9,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
-#include "media/gpu/android/texture_owner.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "media/gpu/media_gpu_export.h"
 
 namespace media {
@@ -23,9 +23,9 @@
     : public base::RefCountedThreadSafe<CodecBufferWaitCoordinator> {
  public:
   explicit CodecBufferWaitCoordinator(
-      scoped_refptr<TextureOwner> texture_owner);
+      scoped_refptr<gpu::TextureOwner> texture_owner);
 
-  scoped_refptr<TextureOwner> texture_owner() { return texture_owner_; }
+  scoped_refptr<gpu::TextureOwner> texture_owner() { return texture_owner_; }
 
   // Codec buffer wait management apis.
   // Sets the expectation of onFrameAVailable for a new frame because a buffer
@@ -50,7 +50,7 @@
  private:
   friend class base::RefCountedThreadSafe<CodecBufferWaitCoordinator>;
 
-  scoped_refptr<TextureOwner> texture_owner_;
+  scoped_refptr<gpu::TextureOwner> texture_owner_;
   base::TimeTicks release_time_;
   scoped_refptr<FrameAvailableEvent> frame_available_event_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc
index 44ca2b3..0966a889 100644
--- a/media/gpu/android/codec_image.cc
+++ b/media/gpu/android/codec_image.cc
@@ -19,7 +19,7 @@
 
 // Makes |texture_owner|'s context current if it isn't already.
 std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded(
-    TextureOwner* texture_owner) {
+    gpu::TextureOwner* texture_owner) {
   gl::GLContext* context = texture_owner->GetContext();
   // Note: this works for virtual contexts too, because IsCurrent() returns true
   // if their shared platform context is current, regardless of which virtual
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h
index c761a4b..d69b238 100644
--- a/media/gpu/android/codec_image.h
+++ b/media/gpu/android/codec_image.h
@@ -108,7 +108,7 @@
     return !!codec_buffer_wait_coordinator_;
   }
 
-  scoped_refptr<TextureOwner> texture_owner() const {
+  scoped_refptr<gpu::TextureOwner> texture_owner() const {
     return codec_buffer_wait_coordinator_
                ? codec_buffer_wait_coordinator_->texture_owner()
                : nullptr;
diff --git a/media/gpu/android/codec_image_unittest.cc b/media/gpu/android/codec_image_unittest.cc
index da201b7..69aae32 100644
--- a/media/gpu/android/codec_image_unittest.cc
+++ b/media/gpu/android/codec_image_unittest.cc
@@ -11,12 +11,12 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/common/android/mock_abstract_texture.h"
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 #include "media/base/android/media_codec_bridge.h"
 #include "media/base/android/mock_media_codec_bridge.h"
 #include "media/gpu/android/codec_image.h"
-#include "media/gpu/android/mock_abstract_texture.h"
 #include "media/gpu/android/mock_codec_buffer_wait_coordinator.h"
-#include "media/gpu/android/mock_texture_owner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -62,7 +62,7 @@
     // The tests rely on this texture being bound.
     glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
 
-    auto texture_owner = base::MakeRefCounted<NiceMock<MockTextureOwner>>(
+    auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
         texture_id_, context_.get(), surface_.get(), BindsTextureOnUpdate());
     codec_buffer_wait_coordinator_ =
         base::MakeRefCounted<NiceMock<MockCodecBufferWaitCoordinator>>(
diff --git a/media/gpu/android/codec_surface_bundle.cc b/media/gpu/android/codec_surface_bundle.cc
index d85eb785..56808e7 100644
--- a/media/gpu/android/codec_surface_bundle.cc
+++ b/media/gpu/android/codec_surface_bundle.cc
@@ -20,7 +20,7 @@
       overlay_(std::move(overlay)) {}
 
 CodecSurfaceBundle::CodecSurfaceBundle(
-    scoped_refptr<TextureOwner> texture_owner)
+    scoped_refptr<gpu::TextureOwner> texture_owner)
     : RefCountedDeleteOnSequence<CodecSurfaceBundle>(
           base::SequencedTaskRunnerHandle::Get()),
       texture_owner_(std::move(texture_owner)),
@@ -40,8 +40,8 @@
     texture_owner_->ReleaseBackBuffers();
   } else {
     task_runner->PostTask(
-        FROM_HERE,
-        base::BindRepeating(&TextureOwner::ReleaseBackBuffers, texture_owner_));
+        FROM_HERE, base::BindRepeating(&gpu::TextureOwner::ReleaseBackBuffers,
+                                       texture_owner_));
   }
 }
 
diff --git a/media/gpu/android/codec_surface_bundle.h b/media/gpu/android/codec_surface_bundle.h
index c02bf89..446c730e8 100644
--- a/media/gpu/android/codec_surface_bundle.h
+++ b/media/gpu/android/codec_surface_bundle.h
@@ -6,8 +6,8 @@
 #define MEDIA_GPU_ANDROID_CODEC_SURFACE_BUNDLE_H_
 
 #include "base/memory/ref_counted_delete_on_sequence.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "media/base/android/android_overlay.h"
-#include "media/gpu/android/surface_texture_gl_owner.h"
 #include "media/gpu/media_gpu_export.h"
 #include "ui/gl/android/scoped_java_surface.h"
 
@@ -27,7 +27,7 @@
   // Create an empty bundle to be manually populated.
   CodecSurfaceBundle();
   explicit CodecSurfaceBundle(std::unique_ptr<AndroidOverlay> overlay);
-  explicit CodecSurfaceBundle(scoped_refptr<TextureOwner> texture_owner);
+  explicit CodecSurfaceBundle(scoped_refptr<gpu::TextureOwner> texture_owner);
 
   const base::android::JavaRef<jobject>& GetJavaSurface() const;
 
@@ -36,7 +36,9 @@
   // |this|; the cb will do nothing if |this| is destroyed.
   ScheduleLayoutCB GetScheduleLayoutCB();
 
-  scoped_refptr<TextureOwner> texture_owner() const { return texture_owner_; }
+  scoped_refptr<gpu::TextureOwner> texture_owner() const {
+    return texture_owner_;
+  }
   AndroidOverlay* overlay() const { return overlay_.get(); }
 
  private:
@@ -49,7 +51,7 @@
   // The Overlay or TextureOwner.
   std::unique_ptr<AndroidOverlay> overlay_;
 
-  scoped_refptr<TextureOwner> texture_owner_;
+  scoped_refptr<gpu::TextureOwner> texture_owner_;
 
   // The Java surface for |texture_owner_|.
   gl::ScopedJavaSurface texture_owner_surface_;
diff --git a/media/gpu/android/direct_shared_image_video_provider.cc b/media/gpu/android/direct_shared_image_video_provider.cc
index 9dcd4a6..a9afe2c 100644
--- a/media/gpu/android/direct_shared_image_video_provider.cc
+++ b/media/gpu/android/direct_shared_image_video_provider.cc
@@ -73,7 +73,7 @@
 void DirectSharedImageVideoProvider::RequestImage(
     ImageReadyCB cb,
     const ImageSpec& spec,
-    scoped_refptr<TextureOwner> texture_owner) {
+    scoped_refptr<gpu::TextureOwner> texture_owner) {
   // It's unclear that we should handle the image group, but since CodecImages
   // have to be registered on it, we do.  If the CodecImage is ever re-used,
   // then part of that re-use would be to call the (then mis-named)
@@ -141,7 +141,7 @@
 void GpuSharedImageVideoFactory::CreateImage(
     FactoryImageReadyCB image_ready_cb,
     const SharedImageVideoProvider::ImageSpec& spec,
-    scoped_refptr<TextureOwner> texture_owner) {
+    scoped_refptr<gpu::TextureOwner> texture_owner) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // Generate a shared image mailbox.
@@ -186,7 +186,7 @@
 
 bool GpuSharedImageVideoFactory::CreateImageInternal(
     const SharedImageVideoProvider::ImageSpec& spec,
-    scoped_refptr<TextureOwner> texture_owner,
+    scoped_refptr<gpu::TextureOwner> texture_owner,
     gpu::Mailbox mailbox,
     scoped_refptr<CodecImage> image) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/media/gpu/android/direct_shared_image_video_provider.h b/media/gpu/android/direct_shared_image_video_provider.h
index 0570ca7d..7225062b 100644
--- a/media/gpu/android/direct_shared_image_video_provider.h
+++ b/media/gpu/android/direct_shared_image_video_provider.h
@@ -14,13 +14,13 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "media/base/video_frame.h"
 #include "media/gpu/android/codec_image.h"
 #include "media/gpu/android/maybe_render_early_manager.h"
 #include "media/gpu/android/shared_image_video_provider.h"
-#include "media/gpu/android/surface_texture_gl_owner.h"
 #include "media/gpu/android/video_frame_factory.h"
 #include "media/gpu/gles2_decoder_helper.h"
 #include "media/gpu/media_gpu_export.h"
@@ -43,7 +43,7 @@
   void Initialize(GpuInitCB get_stub_cb) override;
   void RequestImage(ImageReadyCB cb,
                     const ImageSpec& spec,
-                    scoped_refptr<TextureOwner> texture_owner) override;
+                    scoped_refptr<gpu::TextureOwner> texture_owner) override;
 
  private:
   base::SequenceBound<GpuSharedImageVideoFactory> gpu_factory_;
@@ -80,12 +80,12 @@
   // mailbox support, where we have to have one texture per CodecImage.
   void CreateImage(FactoryImageReadyCB cb,
                    const SharedImageVideoProvider::ImageSpec& spec,
-                   scoped_refptr<TextureOwner> texture_owner);
+                   scoped_refptr<gpu::TextureOwner> texture_owner);
 
  private:
   // Creates a SharedImage for |mailbox|, and returns success or failure.
   bool CreateImageInternal(const SharedImageVideoProvider::ImageSpec& spec,
-                           scoped_refptr<TextureOwner> texture_owner,
+                           scoped_refptr<gpu::TextureOwner> texture_owner,
                            gpu::Mailbox mailbox,
                            scoped_refptr<CodecImage> image);
 
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 9f236963..38bd0b7 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -431,7 +431,7 @@
 }
 
 void MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized(
-    scoped_refptr<TextureOwner> texture_owner) {
+    scoped_refptr<gpu::TextureOwner> texture_owner) {
   DVLOG(2) << __func__;
   TRACE_EVENT0("media",
                "MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized");
diff --git a/media/gpu/android/media_codec_video_decoder.h b/media/gpu/android/media_codec_video_decoder.h
index f4f3b5f..cf2a010 100644
--- a/media/gpu/android/media_codec_video_decoder.h
+++ b/media/gpu/android/media_codec_video_decoder.h
@@ -128,7 +128,7 @@
   // Finishes initialization.
   void StartLazyInit();
   void OnVideoFrameFactoryInitialized(
-      scoped_refptr<TextureOwner> texture_owner);
+      scoped_refptr<gpu::TextureOwner> texture_owner);
 
   // Resets |waiting_for_key_| to false, indicating that MediaCodec might now
   // accept buffers.
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 1b258ea0..573e4ff 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 #include "media/base/android/media_codec_util.h"
 #include "media/base/android/mock_android_overlay.h"
 #include "media/base/android/mock_media_crypto_context.h"
@@ -23,7 +24,6 @@
 #include "media/gpu/android/fake_codec_allocator.h"
 #include "media/gpu/android/mock_android_video_surface_chooser.h"
 #include "media/gpu/android/mock_device_info.h"
-#include "media/gpu/android/mock_texture_owner.h"
 #include "media/gpu/android/video_frame_factory.h"
 #include "media/video/supported_video_decoder_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -66,7 +66,7 @@
   MOCK_METHOD5(
       MockCreateVideoFrame,
       void(CodecOutputBuffer* raw_output_buffer,
-           scoped_refptr<TextureOwner> texture_owner,
+           scoped_refptr<gpu::TextureOwner> texture_owner,
            base::TimeDelta timestamp,
            gfx::Size natural_size,
            PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb));
@@ -103,7 +103,7 @@
   }
 
   std::unique_ptr<CodecOutputBuffer> last_output_buffer_;
-  scoped_refptr<TextureOwner> texture_owner_;
+  scoped_refptr<gpu::TextureOwner> texture_owner_;
   base::OnceClosure last_closure_;
 };
 
@@ -135,8 +135,8 @@
         std::make_unique<NiceMock<MockAndroidVideoSurfaceChooser>>();
     surface_chooser_ = surface_chooser.get();
 
-    auto texture_owner =
-        base::MakeRefCounted<NiceMock<MockTextureOwner>>(0, nullptr, nullptr);
+    auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
+        0, nullptr, nullptr);
     texture_owner_ = texture_owner.get();
 
     auto video_frame_factory =
@@ -284,7 +284,7 @@
   std::unique_ptr<MockDeviceInfo> device_info_;
   std::unique_ptr<FakeCodecAllocator> codec_allocator_;
   MockAndroidVideoSurfaceChooser* surface_chooser_;
-  MockTextureOwner* texture_owner_;
+  gpu::MockTextureOwner* texture_owner_;
   MockVideoFrameFactory* video_frame_factory_;
   NiceMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb_;
   std::unique_ptr<DestructionObserver> destruction_observer_;
diff --git a/media/gpu/android/mock_codec_buffer_wait_coordinator.cc b/media/gpu/android/mock_codec_buffer_wait_coordinator.cc
index bee33e50..ea27522 100644
--- a/media/gpu/android/mock_codec_buffer_wait_coordinator.cc
+++ b/media/gpu/android/mock_codec_buffer_wait_coordinator.cc
@@ -10,7 +10,7 @@
 using testing::Return;
 
 MockCodecBufferWaitCoordinator::MockCodecBufferWaitCoordinator(
-    scoped_refptr<NiceMock<MockTextureOwner>> texture_owner)
+    scoped_refptr<NiceMock<gpu::MockTextureOwner>> texture_owner)
     : CodecBufferWaitCoordinator(texture_owner),
       mock_texture_owner(std::move(texture_owner)),
       expecting_frame_available(false) {
diff --git a/media/gpu/android/mock_codec_buffer_wait_coordinator.h b/media/gpu/android/mock_codec_buffer_wait_coordinator.h
index 5bfb5f4..14fe033b 100644
--- a/media/gpu/android/mock_codec_buffer_wait_coordinator.h
+++ b/media/gpu/android/mock_codec_buffer_wait_coordinator.h
@@ -5,8 +5,8 @@
 #ifndef MEDIA_GPU_ANDROID_MOCK_CODEC_BUFFER_WAIT_COORDINATOR_H_
 #define MEDIA_GPU_ANDROID_MOCK_CODEC_BUFFER_WAIT_COORDINATOR_H_
 
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 #include "media/gpu/android/codec_buffer_wait_coordinator.h"
-#include "media/gpu/android/mock_texture_owner.h"
 
 namespace media {
 
@@ -14,10 +14,10 @@
 class MockCodecBufferWaitCoordinator : public CodecBufferWaitCoordinator {
  public:
   MockCodecBufferWaitCoordinator(
-      scoped_refptr<NiceMock<MockTextureOwner>> texture_owner);
+      scoped_refptr<NiceMock<gpu::MockTextureOwner>> texture_owner);
 
   MOCK_CONST_METHOD0(texture_owner,
-                     scoped_refptr<NiceMock<MockTextureOwner>>());
+                     scoped_refptr<NiceMock<gpu::MockTextureOwner>>());
   MOCK_METHOD0(SetReleaseTimeToNow, void());
   MOCK_METHOD0(IsExpectingFrameAvailable, bool());
   MOCK_METHOD0(WaitForFrameAvailable, void());
@@ -27,7 +27,7 @@
   bool FakeIsExpectingFrameAvailable() { return expecting_frame_available; }
   void FakeWaitForFrameAvailable() { expecting_frame_available = false; }
 
-  scoped_refptr<NiceMock<MockTextureOwner>> mock_texture_owner;
+  scoped_refptr<NiceMock<gpu::MockTextureOwner>> mock_texture_owner;
   bool expecting_frame_available;
 
  protected:
diff --git a/media/gpu/android/shared_image_video_provider.h b/media/gpu/android/shared_image_video_provider.h
index 1b9cedb..269fe0d 100644
--- a/media/gpu/android/shared_image_video_provider.h
+++ b/media/gpu/android/shared_image_video_provider.h
@@ -82,7 +82,7 @@
   // |cb| back before returning, or we might post it for later.
   virtual void RequestImage(ImageReadyCB cb,
                             const ImageSpec& spec,
-                            scoped_refptr<TextureOwner> texture_owner) = 0;
+                            scoped_refptr<gpu::TextureOwner> texture_owner) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SharedImageVideoProvider);
diff --git a/media/gpu/android/video_frame_factory.h b/media/gpu/android/video_frame_factory.h
index 46c3dbd..5b7cc89 100644
--- a/media/gpu/android/video_frame_factory.h
+++ b/media/gpu/android/video_frame_factory.h
@@ -25,7 +25,8 @@
 // safe. Virtual for testing; see VideoFrameFactoryImpl.
 class MEDIA_GPU_EXPORT VideoFrameFactory {
  public:
-  using InitCb = base::RepeatingCallback<void(scoped_refptr<TextureOwner>)>;
+  using InitCb =
+      base::RepeatingCallback<void(scoped_refptr<gpu::TextureOwner>)>;
   using OnceOutputCb = base::OnceCallback<void(scoped_refptr<VideoFrame>)>;
 
   VideoFrameFactory() = default;
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index a2977e30..5c4cae8 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -17,6 +17,7 @@
 #include "base/task_runner_util.h"
 #include "base/trace_event/trace_event.h"
 #include "gpu/command_buffer/service/abstract_texture.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_frame.h"
@@ -32,7 +33,7 @@
 namespace media {
 namespace {
 
-TextureOwner::Mode GetTextureOwnerMode(
+gpu::TextureOwner::Mode GetTextureOwnerMode(
     VideoFrameFactory::OverlayMode overlay_mode) {
   const bool a_image_reader_supported =
       base::android::AndroidImageReader::GetInstance().IsSupported();
@@ -42,18 +43,18 @@
     case VideoFrameFactory::OverlayMode::kRequestPromotionHints:
       return a_image_reader_supported && base::FeatureList::IsEnabled(
                                              media::kAImageReaderVideoOutput)
-                 ? TextureOwner::Mode::kAImageReaderInsecure
-                 : TextureOwner::Mode::kSurfaceTextureInsecure;
+                 ? gpu::TextureOwner::Mode::kAImageReaderInsecure
+                 : gpu::TextureOwner::Mode::kSurfaceTextureInsecure;
     case VideoFrameFactory::OverlayMode::kSurfaceControlSecure:
       DCHECK(a_image_reader_supported);
-      return TextureOwner::Mode::kAImageReaderSecureSurfaceControl;
+      return gpu::TextureOwner::Mode::kAImageReaderSecureSurfaceControl;
     case VideoFrameFactory::OverlayMode::kSurfaceControlInsecure:
       DCHECK(a_image_reader_supported);
-      return TextureOwner::Mode::kAImageReaderInsecureSurfaceControl;
+      return gpu::TextureOwner::Mode::kAImageReaderInsecureSurfaceControl;
   }
 
   NOTREACHED();
-  return TextureOwner::Mode::kSurfaceTextureInsecure;
+  return gpu::TextureOwner::Mode::kSurfaceTextureInsecure;
 }
 
 // Run on the GPU main thread to allocate the texture owner, and return it
@@ -67,9 +68,9 @@
     return;
   }
 
-  std::move(init_cb).Run(
-      TextureOwner::Create(TextureOwner::CreateTexture(shared_context_state),
-                           GetTextureOwnerMode(overlay_mode)));
+  std::move(init_cb).Run(gpu::TextureOwner::Create(
+      gpu::TextureOwner::CreateTexture(shared_context_state),
+      GetTextureOwnerMode(overlay_mode)));
 }
 
 }  // namespace
diff --git a/media/gpu/android/video_frame_factory_impl_unittest.cc b/media/gpu/android/video_frame_factory_impl_unittest.cc
index 322d310c..e7748b77 100644
--- a/media/gpu/android/video_frame_factory_impl_unittest.cc
+++ b/media/gpu/android/video_frame_factory_impl_unittest.cc
@@ -12,10 +12,11 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/common/android/mock_texture_owner.h"
 #include "media/base/limits.h"
+#include "media/gpu/android/codec_buffer_wait_coordinator.h"
 #include "media/gpu/android/maybe_render_early_manager.h"
 #include "media/gpu/android/mock_codec_image.h"
-#include "media/gpu/android/mock_texture_owner.h"
 #include "media/gpu/android/shared_image_video_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -47,7 +48,7 @@
 
   void RequestImage(ImageReadyCB cb,
                     const ImageSpec& spec,
-                    scoped_refptr<TextureOwner> texture_owner) override {
+                    scoped_refptr<gpu::TextureOwner> texture_owner) override {
     cb_ = std::move(cb);
     spec_ = spec;
     texture_owner_ = std::move(texture_owner);
@@ -60,7 +61,7 @@
   // Most recent arguments to RequestImage.
   ImageReadyCB cb_;
   ImageSpec spec_;
-  scoped_refptr<TextureOwner> texture_owner_;
+  scoped_refptr<gpu::TextureOwner> texture_owner_;
 };
 
 class VideoFrameFactoryImplTest : public testing::Test {
@@ -79,7 +80,7 @@
     impl_ = std::make_unique<VideoFrameFactoryImpl>(
         task_runner_, gpu_preferences_, std::move(image_provider),
         std::move(mre_manager));
-    auto texture_owner = base::MakeRefCounted<NiceMock<MockTextureOwner>>(
+    auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
         0, nullptr, nullptr, true);
     auto codec_buffer_wait_coordinator =
         base::MakeRefCounted<CodecBufferWaitCoordinator>(
@@ -137,7 +138,7 @@
       .Times(1)
       .WillOnce(RunOnceCallback<0>(nullptr));
   base::MockCallback<VideoFrameFactory::InitCb> init_cb;
-  EXPECT_CALL(init_cb, Run(scoped_refptr<TextureOwner>(nullptr)));
+  EXPECT_CALL(init_cb, Run(scoped_refptr<gpu::TextureOwner>(nullptr)));
   impl_->Initialize(VideoFrameFactory::OverlayMode::kDontRequestPromotionHints,
                     init_cb.Get());
   base::RunLoop().RunUntilIdle();
@@ -153,8 +154,8 @@
   // Also provide a non-null TextureOwner to it.
   scoped_refptr<CodecSurfaceBundle> surface_bundle =
       base::MakeRefCounted<CodecSurfaceBundle>(
-          base::MakeRefCounted<NiceMock<MockTextureOwner>>(0, nullptr, nullptr,
-                                                           true));
+          base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(0, nullptr,
+                                                                nullptr, true));
   EXPECT_CALL(*mre_manager_raw_, SetSurfaceBundle(surface_bundle));
   impl_->SetSurfaceBundle(surface_bundle);
   base::RunLoop().RunUntilIdle();
diff --git a/media/mojo/services/video_decode_perf_history.cc b/media/mojo/services/video_decode_perf_history.cc
index cb3303c..744faf1 100644
--- a/media/mojo/services/video_decode_perf_history.cc
+++ b/media/mojo/services/video_decode_perf_history.cc
@@ -32,11 +32,27 @@
 const char VideoDecodePerfHistory::kMaxSmoothDroppedFramesPercentParamName[] =
     "smooth_threshold";
 
+const char
+    VideoDecodePerfHistory::kEmeMaxSmoothDroppedFramesPercentParamName[] =
+        "eme_smooth_threshold";
+
 // static
-double VideoDecodePerfHistory::GetMaxSmoothDroppedFramesPercent() {
-  return base::GetFieldTrialParamByFeatureAsDouble(
+double VideoDecodePerfHistory::GetMaxSmoothDroppedFramesPercent(bool is_eme) {
+  double threshold = base::GetFieldTrialParamByFeatureAsDouble(
       kMediaCapabilitiesWithParameters, kMaxSmoothDroppedFramesPercentParamName,
       kMaxSmoothDroppedFramesPercentParamDefault);
+
+  // For EME, the precedence of overrides is:
+  // 1. EME specific override, |k*Eme*MaxSmoothDroppedFramesPercentParamName
+  // 2. Non-EME override, |kMaxSmoothDroppedFramesPercentParamName|
+  // 3. |kMaxSmoothDroppedFramesPercentParamDefault|
+  if (is_eme) {
+    threshold = base::GetFieldTrialParamByFeatureAsDouble(
+        kMediaCapabilitiesWithParameters,
+        kEmeMaxSmoothDroppedFramesPercentParamName, threshold);
+  }
+
+  return threshold;
 }
 
 VideoDecodePerfHistory::VideoDecodePerfHistory(
@@ -134,6 +150,7 @@
 }
 
 void VideoDecodePerfHistory::AssessStats(
+    const VideoDecodeStatsDB::VideoDescKey& key,
     const VideoDecodeStatsDB::DecodeStatsEntry* stats,
     bool* is_smooth,
     bool* is_power_efficient) {
@@ -158,7 +175,9 @@
 
   *is_power_efficient =
       percent_power_efficient >= kMinPowerEfficientDecodedFramePercent;
-  *is_smooth = percent_dropped <= GetMaxSmoothDroppedFramesPercent();
+
+  *is_smooth = percent_dropped <=
+               GetMaxSmoothDroppedFramesPercent(!key.key_system.empty());
 }
 
 void VideoDecodePerfHistory::OnGotStatsForRequest(
@@ -175,7 +194,7 @@
   double percent_dropped = 0;
   double percent_power_efficient = 0;
 
-  AssessStats(stats.get(), &is_smooth, &is_power_efficient);
+  AssessStats(video_key, stats.get(), &is_smooth, &is_power_efficient);
 
   if (stats && stats->frames_decoded) {
     DCHECK(database_success);
@@ -333,7 +352,7 @@
 
   bool past_is_smooth = false;
   bool past_is_efficient = false;
-  AssessStats(past_stats, &past_is_smooth, &past_is_efficient);
+  AssessStats(video_key, past_stats, &past_is_smooth, &past_is_efficient);
   builder.SetPerf_ApiWouldClaimIsSmooth(past_is_smooth);
   builder.SetPerf_ApiWouldClaimIsPowerEfficient(past_is_efficient);
   if (past_stats) {
@@ -349,7 +368,7 @@
 
   bool new_is_smooth = false;
   bool new_is_efficient = false;
-  AssessStats(&new_stats, &new_is_smooth, &new_is_efficient);
+  AssessStats(video_key, &new_stats, &new_is_smooth, &new_is_efficient);
   builder.SetPerf_RecordIsSmooth(new_is_smooth);
   builder.SetPerf_RecordIsPowerEfficient(new_is_efficient);
   builder.SetPerf_VideoFramesDecoded(new_stats.frames_decoded);
diff --git a/media/mojo/services/video_decode_perf_history.h b/media/mojo/services/video_decode_perf_history.h
index 717767d5..7ebf833f 100644
--- a/media/mojo/services/video_decode_perf_history.h
+++ b/media/mojo/services/video_decode_perf_history.h
@@ -53,6 +53,7 @@
       public base::SupportsUserData::Data {
  public:
   static const char kMaxSmoothDroppedFramesPercentParamName[];
+  static const char kEmeMaxSmoothDroppedFramesPercentParamName[];
 
   explicit VideoDecodePerfHistory(
       std::unique_ptr<VideoDecodeStatsDB> db,
@@ -95,7 +96,7 @@
 
   // Decode capabilities will be described as "smooth" whenever the percentage
   // of dropped frames is less-than-or-equal-to this value.
-  static double GetMaxSmoothDroppedFramesPercent();
+  static double GetMaxSmoothDroppedFramesPercent(bool is_eme);
 
   // Track the status of database lazy initialization.
   enum InitStatus {
@@ -162,7 +163,8 @@
                         const VideoDecodeStatsDB::DecodeStatsEntry& new_stats,
                         VideoDecodeStatsDB::DecodeStatsEntry* past_stats);
 
-  void AssessStats(const VideoDecodeStatsDB::DecodeStatsEntry* stats,
+  void AssessStats(const VideoDecodeStatsDB::VideoDescKey& key,
+                   const VideoDecodeStatsDB::DecodeStatsEntry* stats,
                    bool* is_smooth,
                    bool* is_power_efficient);
 
diff --git a/media/mojo/services/video_decode_perf_history_unittest.cc b/media/mojo/services/video_decode_perf_history_unittest.cc
index 30f1eff..0e9c4f6 100644
--- a/media/mojo/services/video_decode_perf_history_unittest.cc
+++ b/media/mojo/services/video_decode_perf_history_unittest.cc
@@ -168,8 +168,8 @@
     GetFakeDB()->CompleteInitialize(initialize_success);
   }
 
-  double GetMaxSmoothDroppedFramesPercent() {
-    return VideoDecodePerfHistory::GetMaxSmoothDroppedFramesPercent();
+  double GetMaxSmoothDroppedFramesPercent(bool is_eme = false) {
+    return VideoDecodePerfHistory::GetMaxSmoothDroppedFramesPercent(is_eme);
   }
 
   // Tests may set this as the callback for VideoDecodePerfHistory::GetPerfInfo
@@ -291,7 +291,7 @@
     // Verify past stats.
     bool past_is_smooth = false;
     bool past_is_efficient = false;
-    perf_history_->AssessStats(old_stats.get(), &past_is_smooth,
+    perf_history_->AssessStats(key, old_stats.get(), &past_is_smooth,
                                &past_is_efficient);
     EXPECT_UKM(UkmEntry::kPerf_ApiWouldClaimIsSmoothName, past_is_smooth);
     EXPECT_UKM(UkmEntry::kPerf_ApiWouldClaimIsPowerEfficientName,
@@ -312,7 +312,8 @@
         new_targets.frames_power_efficient);
     bool new_is_smooth = false;
     bool new_is_efficient = false;
-    perf_history_->AssessStats(&new_stats, &new_is_smooth, &new_is_efficient);
+    perf_history_->AssessStats(key, &new_stats, &new_is_smooth,
+                               &new_is_efficient);
     EXPECT_UKM(UkmEntry::kPerf_RecordIsSmoothName, new_is_smooth);
     EXPECT_UKM(UkmEntry::kPerf_RecordIsPowerEfficientName, new_is_efficient);
     EXPECT_UKM(UkmEntry::kPerf_VideoFramesDecodedName,
@@ -794,11 +795,17 @@
 // To avoid race conditions when setting the parameter, the test sets it when
 // starting and make sure the values recorded to the DB wouldn't be smooth per
 // the default value.
-TEST_P(VideoDecodePerfHistoryParamTest, SmoothThresholdFinchOverride) {
+TEST_P(VideoDecodePerfHistoryParamTest,
+       SmoothThresholdFinchOverride_NoEmeOverride) {
   base::test::ScopedFeatureList scoped_feature_list;
 
+  // EME and non EME threshold should initially be the same (neither is
+  // overridden).
   double previous_smooth_dropped_frames_threshold =
-      GetMaxSmoothDroppedFramesPercent();
+      GetMaxSmoothDroppedFramesPercent(false /* is_eme */);
+  EXPECT_EQ(previous_smooth_dropped_frames_threshold,
+            GetMaxSmoothDroppedFramesPercent(true /* is_eme */));
+
   double new_smooth_dropped_frames_threshold =
       previous_smooth_dropped_frames_threshold / 2;
 
@@ -818,8 +825,14 @@
       media::kMediaCapabilitiesWithParameters, &actual_trial_params));
   EXPECT_EQ(trial_params, actual_trial_params);
 
+  // Non EME threshold is overridden.
   EXPECT_EQ(new_smooth_dropped_frames_threshold,
-            GetMaxSmoothDroppedFramesPercent());
+            GetMaxSmoothDroppedFramesPercent(false /* is_eme */));
+
+  // EME threshold is also implicitly overridden (we didn't set an EME specific
+  // value, so it should defer to the non-EME override).
+  EXPECT_EQ(new_smooth_dropped_frames_threshold,
+            GetMaxSmoothDroppedFramesPercent(true /* is_eme */));
 
   // NOTE: The when the DB initialization is deferred, All EXPECT_CALLs are then
   // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
@@ -892,6 +905,126 @@
   }
 }
 
+TEST_P(VideoDecodePerfHistoryParamTest,
+       SmoothThresholdFinchOverride_WithEmeOverride) {
+  base::test::ScopedFeatureList scoped_feature_list;
+
+  // EME and non EME threshold should initially be the same (neither is
+  // overridden).
+  double previous_smooth_dropped_frames_threshold =
+      GetMaxSmoothDroppedFramesPercent(false /* is_eme */);
+  EXPECT_EQ(previous_smooth_dropped_frames_threshold,
+            GetMaxSmoothDroppedFramesPercent(true /* is_eme */));
+
+  double new_CLEAR_smooth_dropped_frames_threshold =
+      previous_smooth_dropped_frames_threshold / 2;
+  double new_EME_smooth_dropped_frames_threshold =
+      previous_smooth_dropped_frames_threshold / 3;
+
+  ASSERT_LT(new_CLEAR_smooth_dropped_frames_threshold,
+            previous_smooth_dropped_frames_threshold);
+  ASSERT_LT(new_EME_smooth_dropped_frames_threshold,
+            new_CLEAR_smooth_dropped_frames_threshold);
+
+  // Override field trial.
+  base::FieldTrialParams trial_params;
+  trial_params
+      [VideoDecodePerfHistory::kMaxSmoothDroppedFramesPercentParamName] =
+          base::NumberToString(new_CLEAR_smooth_dropped_frames_threshold);
+  trial_params
+      [VideoDecodePerfHistory::kEmeMaxSmoothDroppedFramesPercentParamName] =
+          base::NumberToString(new_EME_smooth_dropped_frames_threshold);
+
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      media::kMediaCapabilitiesWithParameters, trial_params);
+
+  base::FieldTrialParams actual_trial_params;
+  EXPECT_TRUE(base::GetFieldTrialParamsByFeature(
+      media::kMediaCapabilitiesWithParameters, &actual_trial_params));
+  EXPECT_EQ(trial_params, actual_trial_params);
+
+  // Both thresholds should be overridden.
+  EXPECT_EQ(new_CLEAR_smooth_dropped_frames_threshold,
+            GetMaxSmoothDroppedFramesPercent(false /* is_eme */));
+  EXPECT_EQ(new_EME_smooth_dropped_frames_threshold,
+            GetMaxSmoothDroppedFramesPercent(true /* is_eme */));
+
+  // NOTE: The when the DB initialization is deferred, All EXPECT_CALLs are then
+  // delayed until we db_->CompleteInitialize(). testing::InSequence enforces
+  // that EXPECT_CALLs arrive in top-to-bottom order.
+  PerfHistoryTestParams params = GetParam();
+  testing::InSequence dummy;
+
+  // Complete initialization in advance of API calls when not asked to defer.
+  if (!params.defer_initialize)
+    PreInitializeDB(/* success */ true);
+
+  // First add 2 records to the history. The second record has a higher frame
+  // rate and a higher number of dropped frames such that it is "not smooth".
+  const VideoCodecProfile kKnownProfile = VP9PROFILE_PROFILE0;
+  const gfx::Size kKownSize(100, 200);
+  const int kSmoothFrameRatePrevious = 30;
+  const int kSmoothFrameRateNew = 90;
+  const int kFramesDecoded = 1000;
+  const int kNotPowerEfficientFramesDecoded = 0;
+
+  // Sets the ratio of dropped frames to qualify as NOT smooth. For CLEAR, use
+  // the previous smooth threshold. For EME, use the new CLEAR threshold to
+  // verify that the EME threshold is lower than CLEAR.
+  const int kSmoothFramesDroppedPrevious =
+      params.key_system.empty()
+          ? kFramesDecoded * previous_smooth_dropped_frames_threshold
+          : kFramesDecoded * new_CLEAR_smooth_dropped_frames_threshold;
+  // Sets the ratio of dropped frames to quality as smooth per the new threshold
+  // depending on whether the key indicates this record is EME.
+  const int kSmoothFramesDroppedNew =
+      params.key_system.empty()
+          ? kFramesDecoded * new_CLEAR_smooth_dropped_frames_threshold
+          : kFramesDecoded * new_EME_smooth_dropped_frames_threshold;
+
+  // Add the entry.
+  SavePerfRecord(
+      UkmVerifcation::kSaveTriggersUkm, kOrigin, kIsTopFrame,
+      MakeFeatures(kKnownProfile, kKownSize, kSmoothFrameRatePrevious,
+                   params.key_system, params.use_hw_secure_codecs),
+      MakeTargets(kFramesDecoded, kSmoothFramesDroppedPrevious,
+                  kNotPowerEfficientFramesDecoded),
+      kPlayerId);
+
+  SavePerfRecord(UkmVerifcation::kSaveTriggersUkm, kOrigin, kIsTopFrame,
+                 MakeFeatures(kKnownProfile, kKownSize, kSmoothFrameRateNew,
+                              params.key_system, params.use_hw_secure_codecs),
+                 MakeTargets(kFramesDecoded, kSmoothFramesDroppedNew,
+                             kNotPowerEfficientFramesDecoded),
+                 kPlayerId);
+
+  // Verify perf history returns is_smooth = false for entry that would be
+  // smooth per previous smooth threshold.
+  EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth, kIsNotPowerEfficient));
+  perf_history_->GetPerfInfo(
+      MakeFeaturesPtr(kKnownProfile, kKownSize, kSmoothFrameRatePrevious,
+                      params.key_system, params.use_hw_secure_codecs),
+      base::BindOnce(&VideoDecodePerfHistoryParamTest::MockGetPerfInfoCB,
+                     base::Unretained(this)));
+
+  // Verify perf history returns is_smooth = true for entry that would be
+  // smooth per new smooth threshold.
+  EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth, kIsNotPowerEfficient));
+  perf_history_->GetPerfInfo(
+      MakeFeaturesPtr(kKnownProfile, kKownSize, kSmoothFrameRateNew,
+                      params.key_system, params.use_hw_secure_codecs),
+      base::BindOnce(&VideoDecodePerfHistoryParamTest::MockGetPerfInfoCB,
+                     base::Unretained(this)));
+
+  // Complete successful deferred DB initialization (see comment at top of test)
+  if (params.defer_initialize) {
+    GetFakeDB()->CompleteInitialize(true);
+
+    // Allow initialize-deferred API calls to complete.
+    scoped_task_environment_.RunUntilIdle();
+  }
+}
+
 const PerfHistoryTestParams kPerfHistoryTestParams[] = {
     {true, "", false},
     {false, "", false},
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index 0494bca..a9e351a7 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -1282,7 +1282,7 @@
 
     // Upload the CPU-side SkImage into a GPU-side SkImage.
     // (Note the original video_frame data is no longer used after this point.)
-    yuv_images[plane] = plane_image_cpu->makeTextureImage(gr_context, nullptr);
+    yuv_images[plane] = plane_image_cpu->makeTextureImage(gr_context);
     DCHECK(yuv_images[plane]);
 
     // Extract the backend texture from the GPU-side image.
diff --git a/net/base/dir_header.html b/net/base/dir_header.html
index 763ec30..d57f18a 100644
--- a/net/base/dir_header.html
+++ b/net/base/dir_header.html
@@ -123,6 +123,25 @@
     tbody.appendChild(list[i]);
   }
 }
+
+// Add event handlers to column headers.
+function addHandlers(element, column) {
+  element.onclick = (e) => sortTable(column);
+  element.onkeydown = (e) => {
+    if (e.key == 'Enter' || e.key == ' ') {
+      sortTable(column);
+      e.preventDefault();
+    }
+  };
+}
+
+function onLoad() {
+  addHandlers(document.getElementById('nameColumnHeader'), 0);
+  addHandlers(document.getElementById('sizeColumnHeader'), 1);
+  addHandlers(document.getElementById('dateColumnHeader'), 2);
+}
+
+window.addEventListener('DOMContentLoaded', onLoad);
 </script>
 
 <style>
@@ -205,11 +224,11 @@
 <table>
   <thead>
     <tr class="header" id="theader">
-      <th onclick="javascript:sortTable(0);">$i18n{headerName}</th>
-      <th class="detailsColumn" onclick="javascript:sortTable(1);">
+      <th id="nameColumnHeader" tabindex=0 role="button">$i18n{headerName}</th>
+      <th id="sizeColumnHeader" class="detailsColumn" tabindex=0 role="button">
         $i18n{headerSize}
       </th>
-      <th class="detailsColumn" onclick="javascript:sortTable(2);">
+      <th id="dateColumnHeader" class="detailsColumn" tabindex=0 role="button">
         $i18n{headerDateModified}
       </th>
     </tr>
diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc
index c31389f..bd37148 100644
--- a/sandbox/win/tests/validation_tests/suite.cc
+++ b/sandbox/win/tests/validation_tests/suite.cc
@@ -148,7 +148,7 @@
   wchar_t command[1024] = {0};
 
   wsprintf(command, L"ValidWindow %Id",
-           reinterpret_cast<size_t>(::GetDesktopWindow()));
+           reinterpret_cast<size_t>(::GetShellWindow()));
   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
 
   wsprintf(command, L"ValidWindow %Id",
diff --git a/services/media_session/README.md b/services/media_session/README.md
index 64ac936..77b6c93e 100644
--- a/services/media_session/README.md
+++ b/services/media_session/README.md
@@ -10,3 +10,16 @@
 For more details about controlling playback see [controlling Media Playback](https://chromium.googlesource.com/chromium/src/+/master/services/media_session/controlling_media_playback.md).
 
 TODO(beccahughes): Write docs about requesting audio focus.
+
+## Media Session IDs
+
+The Media Session service uses base::UnguessableToken for a number of different
+reasons, these are:
+
+* Request IDs: These identify a single media session
+* Group IDs: These group together a number of media sessions that should share
+  focus, this is usually per-app.
+* Source IDs: These identity a user/profile that created a media session
+
+Every media session has its own unique request ID and it may also have a group
+ID and a source ID.
\ No newline at end of file
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index 6b9c6ac..9c8227e 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -69,7 +69,8 @@
       std::make_unique<AudioFocusRequest>(
           weak_ptr_factory_.GetWeakPtr(), std::move(receiver),
           std::move(media_session), std::move(session_info), type, request_id,
-          GetBindingSourceName(), base::UnguessableToken::Create()),
+          GetBindingSourceName(), base::UnguessableToken::Create(),
+          GetBindingIdentity()),
       type);
 
   std::move(callback).Run(request_id);
@@ -92,7 +93,7 @@
       std::make_unique<AudioFocusRequest>(
           weak_ptr_factory_.GetWeakPtr(), std::move(receiver),
           std::move(media_session), std::move(session_info), type, request_id,
-          GetBindingSourceName(), group_id),
+          GetBindingSourceName(), group_id, GetBindingIdentity()),
       type);
 
   std::move(callback).Run(true /* success */);
@@ -116,6 +117,7 @@
 
     row->ipc()->GetDebugInfo(base::BindOnce(
         [](const base::UnguessableToken& group_id,
+           const base::UnguessableToken& identity,
            GetDebugInfoForRequestCallback callback,
            mojom::MediaSessionDebugInfoPtr info) {
           // Inject the |group_id| into the state string. This is because in
@@ -125,9 +127,12 @@
             info->state += " ";
           info->state += "GroupId=" + group_id.ToString();
 
+          // Inject the identity into the state string.
+          info->state += " Identity=" + identity.ToString();
+
           std::move(callback).Run(std::move(info));
         },
-        row->group_id(), std::move(callback)));
+        row->group_id(), row->identity(), std::move(callback)));
     return;
   }
 
@@ -170,9 +175,13 @@
   observers_.Add(std::move(observer));
 }
 
-void AudioFocusManager::SetSourceName(const std::string& name) {
+void AudioFocusManager::SetSource(const base::UnguessableToken& identity,
+                                  const std::string& name) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  bindings_.dispatch_context()->source_name = name;
+
+  auto& context = bindings_.dispatch_context();
+  context->identity = identity;
+  context->source_name = name;
 }
 
 void AudioFocusManager::SetEnforcementMode(mojom::EnforcementMode mode) {
@@ -340,6 +349,11 @@
   return bindings_.dispatch_context()->source_name;
 }
 
+const base::UnguessableToken& AudioFocusManager::GetBindingIdentity() const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  return bindings_.dispatch_context()->identity;
+}
+
 bool AudioFocusManager::IsSessionOnTopOfAudioFocusStack(
     RequestId id,
     mojom::AudioFocusType type) const {
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h
index dd6bf01..8252577 100644
--- a/services/media_session/audio_focus_manager.h
+++ b/services/media_session/audio_focus_manager.h
@@ -66,7 +66,8 @@
   void GetFocusRequests(GetFocusRequestsCallback callback) override;
   void AddObserver(
       mojo::PendingRemote<mojom::AudioFocusObserver> observer) override;
-  void SetSourceName(const std::string& name) override;
+  void SetSource(const base::UnguessableToken& identity,
+                 const std::string& name) override;
   void SetEnforcementMode(mojom::EnforcementMode mode) override;
 
   // mojom::AudioFocusManagerDebug.
@@ -104,6 +105,9 @@
     // service_manager::Identity for metrics and for identifying where an audio
     // focus request originated from.
     std::string source_name;
+
+    // The identity associated with the binding when it was created.
+    base::UnguessableToken identity;
   };
 
   void RequestAudioFocusInternal(std::unique_ptr<AudioFocusRequest>,
@@ -122,6 +126,10 @@
   // Focus Manager API over mojo.
   const std::string& GetBindingSourceName() const;
 
+  // Returns the identity of the binding currently accessing the Audio Focus
+  // Manager API over mojo.
+  const base::UnguessableToken& GetBindingIdentity() const;
+
   bool IsSessionOnTopOfAudioFocusStack(RequestId id,
                                        mojom::AudioFocusType type) const;
 
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc
index 6095a4e5..05e576c 100644
--- a/services/media_session/audio_focus_manager_unittest.cc
+++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -18,6 +18,7 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/media_session/audio_focus_manager_metrics_helper.h"
+#include "services/media_session/audio_focus_request.h"
 #include "services/media_session/media_session_service.h"
 #include "services/media_session/public/cpp/test/audio_focus_test_util.h"
 #include "services/media_session/public/cpp/test/mock_media_session.h"
@@ -166,8 +167,9 @@
     return mojom::MediaSessionInfo::SessionState::kActive;
   }
 
-  void SetSourceName(const std::string& name) {
-    GetService()->SetSourceName(name);
+  void SetSource(const base::UnguessableToken& identity,
+                 const std::string& name) {
+    GetService()->SetSource(identity, name);
     audio_focus_remote_.FlushForTesting();
   }
 
@@ -216,6 +218,12 @@
     return controller_manager_remote_;
   }
 
+  const base::UnguessableToken& GetIdentityForLastRequest() const {
+    return service_->audio_focus_manager_for_testing()
+        .audio_focus_stack_.back()
+        ->identity();
+  }
+
  private:
   int GetCountForType(mojom::AudioFocusType type) {
     const auto audio_focus_requests = GetRequests();
@@ -861,40 +869,54 @@
             GetState(&media_session_1));
 }
 
-TEST_P(AudioFocusManagerTest, SourceName_AssociatedWithBinding) {
-  SetSourceName(kExampleSourceName);
+TEST_P(AudioFocusManagerTest, Source_AssociatedWithBinding) {
+  base::UnguessableToken identity = base::UnguessableToken::Create();
+  SetSource(identity, kExampleSourceName);
 
+  base::UnguessableToken new_identity = base::UnguessableToken::Create();
   mojo::Remote<mojom::AudioFocusManager> new_ptr =
       CreateAudioFocusManagerRemote();
-  new_ptr->SetSourceName(kExampleSourceName2);
+  new_ptr->SetSource(new_identity, kExampleSourceName2);
   new_ptr.FlushForTesting();
 
-  test::MockMediaSession media_session;
-  RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
+  test::MockMediaSession media_session_1;
+  RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
+  EXPECT_EQ(identity, GetIdentityForLastRequest());
+
+  test::MockMediaSession media_session_2;
+  media_session_2.RequestAudioFocusFromService(new_ptr,
+                                               mojom::AudioFocusType::kGain);
+  EXPECT_EQ(kExampleSourceName2, GetSourceNameForLastRequest());
+  EXPECT_EQ(new_identity, GetIdentityForLastRequest());
 }
 
-TEST_P(AudioFocusManagerTest, SourceName_Empty) {
+TEST_P(AudioFocusManagerTest, Source_Empty) {
   test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_TRUE(GetSourceNameForLastRequest().empty());
+  EXPECT_EQ(base::UnguessableToken::Null(), GetIdentityForLastRequest());
 }
 
-TEST_P(AudioFocusManagerTest, SourceName_Updated) {
-  SetSourceName(kExampleSourceName);
+TEST_P(AudioFocusManagerTest, Source_Updated) {
+  base::UnguessableToken identity = base::UnguessableToken::Create();
+  SetSource(identity, kExampleSourceName);
 
   test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
+  EXPECT_EQ(identity, GetIdentityForLastRequest());
 
-  SetSourceName(kExampleSourceName2);
+  base::UnguessableToken new_identity = base::UnguessableToken::Create();
+  SetSource(new_identity, kExampleSourceName2);
   EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
+  EXPECT_EQ(identity, GetIdentityForLastRequest());
 }
 
 TEST_P(AudioFocusManagerTest, RecordUmaMetrics) {
   EXPECT_EQ(0, GetAudioFocusHistogramCount());
 
-  SetSourceName(kExampleSourceName);
+  SetSource(base::UnguessableToken::Create(), kExampleSourceName);
   test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient);
 
@@ -961,7 +983,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RecordUmaMetrics_ConnectionError) {
-  SetSourceName(kExampleSourceName);
+  SetSource(base::UnguessableToken::Create(), kExampleSourceName);
 
   {
     test::MockMediaSession media_session;
diff --git a/services/media_session/audio_focus_request.cc b/services/media_session/audio_focus_request.cc
index 9b4f980..aecdd2d 100644
--- a/services/media_session/audio_focus_request.cc
+++ b/services/media_session/audio_focus_request.cc
@@ -16,7 +16,8 @@
     mojom::AudioFocusType audio_focus_type,
     const base::UnguessableToken& id,
     const std::string& source_name,
-    const base::UnguessableToken& group_id)
+    const base::UnguessableToken& group_id,
+    const base::UnguessableToken& identity)
     : metrics_helper_(source_name),
       session_(std::move(session)),
       session_info_(std::move(session_info)),
@@ -25,6 +26,7 @@
       id_(id),
       source_name_(source_name),
       group_id_(group_id),
+      identity_(identity),
       owner_(std::move(owner)) {
   // Listen for mojo errors.
   receiver_.set_disconnect_handler(base::BindOnce(
diff --git a/services/media_session/audio_focus_request.h b/services/media_session/audio_focus_request.h
index cbe77a6..326343ec 100644
--- a/services/media_session/audio_focus_request.h
+++ b/services/media_session/audio_focus_request.h
@@ -31,7 +31,8 @@
       mojom::AudioFocusType audio_focus_type,
       const base::UnguessableToken& id,
       const std::string& source_name,
-      const base::UnguessableToken& group_id);
+      const base::UnguessableToken& group_id,
+      const base::UnguessableToken& identity);
 
   ~AudioFocusRequest() override;
 
@@ -80,6 +81,7 @@
   const base::UnguessableToken& id() const { return id_; }
   const std::string& source_name() const { return source_name_; }
   const base::UnguessableToken& group_id() const { return group_id_; }
+  const base::UnguessableToken& identity() const { return identity_; }
 
  private:
   void SetSessionInfo(mojom::MediaSessionInfoPtr session_info);
@@ -113,6 +115,9 @@
   // The group ID of the audio focus request.
   base::UnguessableToken const group_id_;
 
+  // The identity that requested audio focus.
+  base::UnguessableToken const identity_;
+
   // Weak pointer to the owning |AudioFocusManager| instance.
   const base::WeakPtr<AudioFocusManager> owner_;
 
diff --git a/services/media_session/media_session_service.h b/services/media_session/media_session_service.h
index 37f3276..dd65639f 100644
--- a/services/media_session/media_session_service.h
+++ b/services/media_session/media_session_service.h
@@ -29,9 +29,14 @@
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
 
+  const AudioFocusManager& audio_focus_manager_for_testing() const {
+    return *audio_focus_manager_.get();
+  }
+
  private:
   service_manager::ServiceBinding service_binding_;
   service_manager::BinderRegistry registry_;
+
   std::unique_ptr<AudioFocusManager> audio_focus_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSessionService);
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom
index cba9d4b..7086a8ad 100644
--- a/services/media_session/public/mojom/audio_focus.mojom
+++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -7,7 +7,7 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "services/media_session/public/mojom/media_session.mojom";
 
-// Next MinVersion: 6
+// Next MinVersion: 7
 
 // These are the different modes the AudioFocusManager can enforce audio focus.
 [Extensible]
@@ -87,8 +87,11 @@
   MediaSessionInfoChanged@2(MediaSessionInfo session_info);
 };
 
-// Controls audio focus across the entire system.
-// Next Method ID: 6
+// Controls audio focus across the entire system. After binding
+// AudioFocusManager clients should call SetSource to identify themselves to
+// the media session service.
+// Next Method ID: 7
+// Deprecated method IDs: 3
 interface AudioFocusManager {
   // Requests audio focus with |type| for the |media_session| with
   // |session_info|. Media sessions should provide a |request| that will
@@ -123,11 +126,14 @@
   // Adds observers that receive audio focus events.
   AddObserver@2(pending_remote<AudioFocusObserver> observer);
 
-  // Associates a name with this binding. This will be associated with all
-  // audio focus requests made with this binding. It will also be used for
-  // associating metrics to a source. If the source name is updated then
+  // Associates a source with this binding. This will be associated with all
+  // audio focus requests made with this binding and we expect that this should
+  // be called at most once per binding. The |identity| will be used for
+  // filtering requests from the same context (e.g. profile). The |name| will
+  // be used for associating metrics to a source. If the source is updated then
   // the audio focus requests will retain the previous source name.
-  [MinVersion=2] SetSourceName@3(string name);
+  [MinVersion=6] SetSource@6(
+      mojo_base.mojom.UnguessableToken identity, string name);
 
   // Sets the enforcement mode for the Audio Focus Manager.
   [MinVersion=5] SetEnforcementMode@5(EnforcementMode mode);
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index a1d008a..35aceedd 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -29,6 +29,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
 #include "mojo/public/c/system/types.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -842,7 +843,13 @@
   EXPECT_EQ(1, num_redirects);
 }
 
-TEST_P(SimpleURLLoaderTest, UploadLongStringWithRedirect) {
+#if defined(OS_FUCHSIA)
+// TODO(crbug.com/994007): The test crashes on Fuchsia.
+#define MAYBE_UploadLongStringWithRedirect DISABLED_UploadLongStringWithRedirect
+#else
+#define MAYBE_UploadLongStringWithRedirect UploadLongStringWithRedirect
+#endif
+TEST_P(SimpleURLLoaderTest, MAYBE_UploadLongStringWithRedirect) {
   // Use a 307 redirect to preserve the body across the redirect.
   std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelperForURL(
       test_server_.GetURL("/server-redirect-307?" +
diff --git a/services/network/resource_scheduler/resource_scheduler.cc b/services/network/resource_scheduler/resource_scheduler.cc
index 84918fea..0f57bff0 100644
--- a/services/network/resource_scheduler/resource_scheduler.cc
+++ b/services/network/resource_scheduler/resource_scheduler.cc
@@ -581,6 +581,19 @@
     if (p2p_connections_count_ == count)
       return;
 
+    if (p2p_connections_count_ > 0 && count == 0) {
+      // If the count of P2P connections went down to 0, start a timer. When the
+      // timer fires, the queued browser-initiated requests would be dispatched.
+      p2p_connections_count_end_timestamp_ = tick_clock_->NowTicks();
+      p2p_connections_count_ended_timer_.Stop();
+      p2p_connections_count_ended_timer_.Start(
+          FROM_HERE,
+          resource_scheduler_->resource_scheduler_params_manager_
+              .TimeToPauseHeavyBrowserInitiatedRequestsAfterEndOfP2PConnections(),
+          this,
+          &ResourceScheduler::Client::OnP2PConnectionsCountEndedTimerFired);
+    }
+
     p2p_connections_count_ = count;
 
     if (p2p_connections_count_ > 0 &&
@@ -597,6 +610,13 @@
         RequestStartTrigger::PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED);
   }
 
+  void OnP2PConnectionsCountEndedTimerFired() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+    LoadAnyStartablePendingRequests(
+        RequestStartTrigger::PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED);
+  }
+
   // Records the metrics related to number of requests in flight.
   void RecordRequestCountMetrics() const {
     UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.All",
@@ -884,8 +904,29 @@
       return false;
     }
 
-    if (p2p_connections_count_ == 0)
-      return false;
+    if (p2p_connections_count_ == 0) {
+      // If the current count of P2P connections is 0, then check when was the
+      // last time when there was an active P2P connection. If that timestamp is
+      // recent, it's a heuristic indication that a new P2P connection may
+      // start soon. To avoid network contention for that connection, keep
+      // throttling browser-initiated requests.
+      if (!p2p_connections_count_end_timestamp_.has_value())
+        return false;
+
+      bool p2p_connections_ended_long_back =
+          (tick_clock_->NowTicks() -
+           p2p_connections_count_end_timestamp_.value()) >=
+          resource_scheduler_->resource_scheduler_params_manager_
+              .TimeToPauseHeavyBrowserInitiatedRequestsAfterEndOfP2PConnections();
+      if (p2p_connections_ended_long_back)
+        return false;
+
+      // If there are no currently active P2P connections, and the last
+      // connection ended recently, then |p2p_connections_count_ended_timer_|
+      // must be running. When |p2p_connections_count_ended_timer_| fires,
+      // queued browser-initiated requests would be dispatched.
+      DCHECK(p2p_connections_count_ended_timer_.IsRunning());
+    }
 
     // Only throttle when effective connection type is between Slow2G and 3G.
     if (effective_connection_type_ <= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE ||
@@ -896,17 +937,19 @@
     if (request.url_request()->priority() == net::HIGHEST)
       return false;
 
-    base::TimeDelta time_since_p2p_connections_active =
-        tick_clock_->NowTicks() -
-        p2p_connections_count_active_timestamp_.value();
+    if (p2p_connections_count_ > 0) {
+      base::TimeDelta time_since_p2p_connections_active =
+          tick_clock_->NowTicks() -
+          p2p_connections_count_active_timestamp_.value();
 
-    base::Optional<base::TimeDelta> max_wait_time_p2p_connections =
-        resource_scheduler_->resource_scheduler_params_manager_
-            .max_wait_time_p2p_connections();
+      base::Optional<base::TimeDelta> max_wait_time_p2p_connections =
+          resource_scheduler_->resource_scheduler_params_manager_
+              .max_wait_time_p2p_connections();
 
-    if (time_since_p2p_connections_active >
-        max_wait_time_p2p_connections.value()) {
-      return false;
+      if (time_since_p2p_connections_active >
+          max_wait_time_p2p_connections.value()) {
+        return false;
+      }
     }
 
     // Check other request specific constraints.
@@ -1273,6 +1316,13 @@
   // |p2p_connections_count_| becomes 0.
   base::Optional<base::TimeTicks> p2p_connections_count_active_timestamp_;
 
+  // Earliest timestamp since when the count of active peer to peer
+  // connection counts dropped from a non-zero value to zero. Set to current
+  // timestamp when |p2p_connections_count_| changes from a non-zero value to 0.
+  base::Optional<base::TimeTicks> p2p_connections_count_end_timestamp_;
+
+  base::OneShotTimer p2p_connections_count_ended_timer_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_{this};
diff --git a/services/network/resource_scheduler/resource_scheduler_params_manager.cc b/services/network/resource_scheduler/resource_scheduler_params_manager.cc
index d44244f..cb5bab59 100644
--- a/services/network/resource_scheduler/resource_scheduler_params_manager.cc
+++ b/services/network/resource_scheduler/resource_scheduler_params_manager.cc
@@ -345,4 +345,13 @@
          throttled_traffic_annotation_hashes_.end();
 }
 
+base::TimeDelta ResourceSchedulerParamsManager::
+    TimeToPauseHeavyBrowserInitiatedRequestsAfterEndOfP2PConnections() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
+      features::kPauseBrowserInitiatedHeavyTrafficForP2P,
+      "seconds_to_pause_requests_after_end_of_p2p_connections", 60));
+}
+
 }  // namespace network
diff --git a/services/network/resource_scheduler/resource_scheduler_params_manager.h b/services/network/resource_scheduler/resource_scheduler_params_manager.h
index 3bb4eb7..7f1eba7 100644
--- a/services/network/resource_scheduler/resource_scheduler_params_manager.h
+++ b/services/network/resource_scheduler/resource_scheduler_params_manager.h
@@ -102,6 +102,11 @@
   bool CanThrottleNetworkTrafficAnnotationHash(
       const int32_t unique_id_hash_code) const;
 
+  // Returns the duration for which heavy browser initiated traffic should be
+  // paused after all P2P connections have finished.
+  base::TimeDelta
+  TimeToPauseHeavyBrowserInitiatedRequestsAfterEndOfP2PConnections();
+
  private:
   // The number of delayable requests in-flight for different ranges of the
   // network quality.
diff --git a/services/network/resource_scheduler/resource_scheduler_unittest.cc b/services/network/resource_scheduler/resource_scheduler_unittest.cc
index e4bd367..ca4ee5f 100644
--- a/services/network/resource_scheduler/resource_scheduler_unittest.cc
+++ b/services/network/resource_scheduler/resource_scheduler_unittest.cc
@@ -855,40 +855,61 @@
 // Verify that browser requests that are currently queued are dispatched to the
 // network as soon as the active P2P connections count drops to 0.
 TEST_F(ResourceSchedulerTest, P2PConnectionWentAway) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  base::HistogramTester histogram_tester;
-  base::FieldTrialParams field_trial_params;
-  field_trial_params["throttled_traffic_annotation_tags"] = "727528";
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kPauseBrowserInitiatedHeavyTrafficForP2P, field_trial_params);
-  InitializeScheduler();
+  const struct {
+    int seconds_to_pause_requests_after_end_of_p2p_connections;
+    bool expect_lows_started;
+  } tests[] = {
+      {// When |seconds_to_pause_requests_after_end_of_p2p_connections| is 0,
+       // running the RunLoop should cause the timer to fire and dispatch
+       // queued browser-initiated requests.
+       0, true},
+      {60, false},
+  };
 
-  network_quality_estimator_
-      .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(1u);
-  network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType(
-      net::EFFECTIVE_CONNECTION_TYPE_2G);
+  for (const auto& test : tests) {
+    base::test::ScopedFeatureList scoped_feature_list;
+    base::HistogramTester histogram_tester;
+    base::FieldTrialParams field_trial_params;
+    field_trial_params["throttled_traffic_annotation_tags"] = "727528";
+    field_trial_params
+        ["seconds_to_pause_requests_after_end_of_p2p_connections"] =
+            base::NumberToString(
+                test.seconds_to_pause_requests_after_end_of_p2p_connections);
+    scoped_feature_list.InitAndEnableFeatureWithParameters(
+        features::kPauseBrowserInitiatedHeavyTrafficForP2P, field_trial_params);
+    InitializeScheduler();
 
-  std::string url = "http://host/browser-initiatited";
+    network_quality_estimator_
+        .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(1u);
+    network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType(
+        net::EFFECTIVE_CONNECTION_TYPE_2G);
 
-  net::NetworkTrafficAnnotationTag tag = net::DefineNetworkTrafficAnnotation(
-      "metrics_report_uma",
-      "Traffic annotation for unit, browser and other tests");
-  // (COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(""));
-  std::unique_ptr<TestRequest> lows = (NewBrowserRequestWithAnnotationTag(
-      url.c_str(), net::LOWEST, tag));  //"metrics_report_uma"));
-  EXPECT_FALSE(lows->started());
+    std::string url = "http://host/browser-initiatited";
 
-  network_quality_estimator_
-      .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(2u);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(lows->started());
+    net::NetworkTrafficAnnotationTag tag = net::DefineNetworkTrafficAnnotation(
+        "metrics_report_uma",
+        "Traffic annotation for unit, browser and other tests");
+    // (COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(""));
+    std::unique_ptr<TestRequest> lows = (NewBrowserRequestWithAnnotationTag(
+        url.c_str(), net::LOWEST, tag));  //"metrics_report_uma"));
+    EXPECT_FALSE(lows->started());
 
-  network_quality_estimator_
-      .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(0u);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(lows->started());
-  histogram_tester.ExpectTotalCount(
-      "ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration", 1u);
+    network_quality_estimator_
+        .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(2u);
+    base::RunLoop().RunUntilIdle();
+    EXPECT_FALSE(lows->started());
+
+    network_quality_estimator_
+        .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(0u);
+    EXPECT_FALSE(lows->started());
+
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(test.expect_lows_started, lows->started());
+
+    histogram_tester.ExpectTotalCount(
+        "ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration",
+        test.expect_lows_started ? 1u : 0u);
+  }
 }
 
 // Verify that the previously queued browser requests are dispatched to the
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index 3cba583e..d672065 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"  // for FALLTHROUGH;
 #include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_util.h"
@@ -485,7 +486,13 @@
   base::debug::SetCrashKeyString(url_origin,
                                  url::Origin::Create(url).GetDebugString());
 
-  mojo::ReportBadMessage("Incorrect url origin");
+  if (url.IsAboutBlank() || url.IsAboutSrcdoc()) {
+    // Temporary mitigation for 983090, classification improvement for parts of
+    // 992587.
+    base::debug::DumpWithoutCrashing();
+  } else {
+    mojo::ReportBadMessage("Incorrect url origin");
+  }
   return false;
 }
 
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index db0ce794..555ca87 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -13102,7 +13102,6 @@
           "--recover-devices",
           "--test-filter=-org.chromium.chrome.browser.metrics.StartupLoadingMetricsTest#testStartWithURLRecorded"
         ],
-        "experiment_percentage": 100,
         "merge": {
           "args": [
             "--bucket",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index b5cf261..85809b6 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -310,9 +310,6 @@
         },
       },
       'Marshmallow 64 bit Tester': {
-        # TODO(crbug.com/731759): Enable this once we're confident that it
-        # passes.
-        'experiment_percentage': 100,
         'swarming': {
           'shards': 14,
         },
diff --git a/testing/perf/BUILD.gn b/testing/perf/BUILD.gn
index 949f15ab..4d47534e 100644
--- a/testing/perf/BUILD.gn
+++ b/testing/perf/BUILD.gn
@@ -5,6 +5,8 @@
 source_set("perf") {
   testonly = true
   sources = [
+    "perf_result_reporter.cc",
+    "perf_result_reporter.h",
     "perf_test.cc",
     "perf_test.h",
   ]
diff --git a/testing/perf/perf_result_reporter.cc b/testing/perf/perf_result_reporter.cc
new file mode 100644
index 0000000..cb7e42a6
--- /dev/null
+++ b/testing/perf/perf_result_reporter.cc
@@ -0,0 +1,62 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/perf/perf_result_reporter.h"
+#include "base/logging.h"
+#include "testing/perf/perf_test.h"
+
+namespace perf_test {
+
+PerfResultReporter::PerfResultReporter(const std::string& metric_basename,
+                                       const std::string& story_name)
+    : metric_basename_(metric_basename), story_name_(story_name) {}
+
+PerfResultReporter::~PerfResultReporter() = default;
+
+void PerfResultReporter::RegisterFyiMetric(const std::string& metric_suffix,
+                                           const std::string& units) {
+  RegisterMetric(metric_suffix, units, false);
+}
+
+void PerfResultReporter::RegisterImportantMetric(
+    const std::string& metric_suffix,
+    const std::string& units) {
+  RegisterMetric(metric_suffix, units, true);
+}
+
+void PerfResultReporter::AddResult(const std::string& metric_suffix,
+                                   size_t value) {
+  auto iter = metric_map_.find(metric_suffix);
+  CHECK(iter != metric_map_.end());
+
+  PrintResult(metric_basename_, metric_suffix, story_name_, value,
+              iter->second.units, iter->second.important);
+}
+
+void PerfResultReporter::AddResult(const std::string& metric_suffix,
+                                   double value) {
+  auto iter = metric_map_.find(metric_suffix);
+  CHECK(iter != metric_map_.end());
+
+  PrintResult(metric_basename_, metric_suffix, story_name_, value,
+              iter->second.units, iter->second.important);
+}
+
+void PerfResultReporter::AddResult(const std::string& metric_suffix,
+                                   const std::string& value) {
+  auto iter = metric_map_.find(metric_suffix);
+  CHECK(iter != metric_map_.end());
+
+  PrintResult(metric_basename_, metric_suffix, story_name_, value,
+              iter->second.units, iter->second.important);
+}
+
+void PerfResultReporter::RegisterMetric(const std::string& metric_suffix,
+                                        const std::string& units,
+                                        bool important) {
+  CHECK(metric_map_.count(metric_suffix) == 0);
+  metric_map_.insert({metric_suffix, {units, important}});
+}
+
+}  // namespace perf_test
diff --git a/testing/perf/perf_result_reporter.h b/testing/perf/perf_result_reporter.h
new file mode 100644
index 0000000..5e6001e8
--- /dev/null
+++ b/testing/perf/perf_result_reporter.h
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_PERF_PERF_RESULT_REPORTER_H_
+#define TESTING_PERF_PERF_RESULT_REPORTER_H_
+
+#include <string>
+#include <unordered_map>
+
+namespace perf_test {
+
+struct MetricInfo {
+  std::string units;
+  bool important;
+};
+
+// A helper class for using the perf test printing functions safely, as
+// otherwise it's easy to accidentally mix up arguments to produce usable but
+// malformed perf data. See https://crbug.com/923564.
+
+// Sample usage:
+// auto reporter = PerfResultReporter("TextRendering", "100_chars");
+// reporter.RegisterImportantMetric(".wall_time", "ms");
+// reporter.RegisterImportantMetric(".cpu_time", "ms");
+// ...
+// reporter.AddResult(".wall_time", GetWallTime());
+// reporter.AddResult(".cpu_time", GetCpuTime());
+
+// This would end up reporting "TextRendering.wall_time" and
+// "TextRendering.cpu_time" metrics on the dashboard, made up of results from
+// a single "100_chars" story. If an additional story run is added, e.g.
+// "200_chars", then the metrics will be averaged over both runs with the
+// ability to drill down into results for specific stories.
+class PerfResultReporter {
+ public:
+  PerfResultReporter(const std::string& metric_basename,
+                     const std::string& story_name);
+  ~PerfResultReporter();
+
+  void RegisterFyiMetric(const std::string& metric_suffix,
+                         const std::string& units);
+  void RegisterImportantMetric(const std::string& metric_suffix,
+                               const std::string& units);
+  void AddResult(const std::string& metric_suffix, size_t value);
+  void AddResult(const std::string& metric_suffix, double value);
+  void AddResult(const std::string& metric_suffix, const std::string& value);
+
+ private:
+  void RegisterMetric(const std::string& metric_suffix,
+                      const std::string& units,
+                      bool important);
+
+  std::string metric_basename_;
+  std::string story_name_;
+  std::unordered_map<std::string, MetricInfo> metric_map_;
+};
+
+}  // namespace perf_test
+
+#endif  // TESTING_PERF_PERF_RESULT_REPORTER_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f67951a..c1042e9 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5118,6 +5118,21 @@
             ]
         }
     ],
+    "ServiceManagerForBackgroundPrefetch": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ServiceManagerForBackgroundPrefetch"
+                    ]
+                }
+            ]
+        }
+    ],
     "ServiceWorkerAggressiveCodeCache": [
         {
             "platforms": [
diff --git a/third_party/android_sdk/BUILD.gn b/third_party/android_sdk/BUILD.gn
index d9412ef..02cca3a 100644
--- a/third_party/android_sdk/BUILD.gn
+++ b/third_party/android_sdk/BUILD.gn
@@ -90,14 +90,4 @@
   android_java_prebuilt("android_gcm_java") {
     jar_path = "//third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar"
   }
-
-  # The current version of //third_party/byte_buddy relies on an older
-  # version of dx.
-  java_prebuilt("dx_25_0_2_java") {
-    supports_android = true
-    requires_android = true
-    no_build_hooks = true
-    testonly = true
-    jar_path = "//third_party/android_sdk/public/build-tools/25.0.2/lib/dx.jar"
-  }
 }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ad10861..6e1cf3f 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8217,7 +8217,8 @@
 void Document::ReportFeaturePolicyViolation(
     mojom::FeaturePolicyFeature feature,
     mojom::FeaturePolicyDisposition disposition,
-    const String& message) const {
+    const String& message,
+    const String& source_file) const {
   if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled(this))
     return;
   LocalFrame* frame = GetFrame();
@@ -8226,12 +8227,18 @@
 
   // Construct the feature policy violation report.
   const String& feature_name = GetNameForFeature(feature);
+  const String& disp_str =
+      (disposition == mojom::FeaturePolicyDisposition::kReport ? "report"
+                                                               : "enforce");
+
   FeaturePolicyViolationReportBody* body =
-      MakeGarbageCollected<FeaturePolicyViolationReportBody>(
-          feature_name, "Feature policy violation",
-          (disposition == mojom::FeaturePolicyDisposition::kReport
-               ? "report"
-               : "enforce"));
+      source_file.IsEmpty()
+          ? MakeGarbageCollected<FeaturePolicyViolationReportBody>(
+                feature_name, "Feature policy violation", disp_str)
+          : MakeGarbageCollected<FeaturePolicyViolationReportBody>(
+                feature_name, "Feature policy violation", disp_str,
+                source_file);
+
   Report* report = MakeGarbageCollected<Report>(
       ReportType::kFeaturePolicyViolation, Url().GetString(), body);
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 2268df8..280af0b 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1500,7 +1500,10 @@
   void ReportFeaturePolicyViolation(
       mojom::FeaturePolicyFeature,
       mojom::FeaturePolicyDisposition,
-      const String& message = g_empty_string) const override;
+      const String& message = g_empty_string,
+      // If source_file is set to empty string,
+      // current JS file would be used as source_file instead.
+      const String& source_file = g_empty_string) const override;
 
   void IncrementNumberOfCanvases();
 
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index c6bb8bc0..7477f4b76 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -168,18 +168,20 @@
 
 bool SecurityContext::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
                                        ReportOptions report_on_failure,
-                                       const String& message) const {
+                                       const String& message,
+                                       const String& source_file) const {
   return IsFeatureEnabled(
       feature,
       PolicyValue::CreateMaxPolicyValue(
           feature_policy_->GetFeatureList().at(feature).second),
-      report_on_failure, message);
+      report_on_failure, message, source_file);
 }
 
 bool SecurityContext::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
                                        PolicyValue threshold_value,
                                        ReportOptions report_on_failure,
-                                       const String& message) const {
+                                       const String& message,
+                                       const String& source_file) const {
   if (report_on_failure == ReportOptions::kReportOnFailure) {
     // We are expecting a violation report in case the feature is disabled in
     // the context. Therefore, this qualifies as a potential violation (i.e.,
@@ -196,7 +198,7 @@
         (state == FeatureEnabledState::kReportOnly
              ? mojom::FeaturePolicyDisposition::kReport
              : mojom::FeaturePolicyDisposition::kEnforce),
-        message);
+        message, source_file);
   }
   return (state != FeatureEnabledState::kDisabled);
 }
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index 4aad2bb..c683c54 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -154,12 +154,14 @@
   bool IsFeatureEnabled(
       mojom::FeaturePolicyFeature,
       ReportOptions report_on_failure = ReportOptions::kDoNotReport,
-      const String& message = g_empty_string) const;
+      const String& message = g_empty_string,
+      const String& source_file = g_empty_string) const;
   bool IsFeatureEnabled(
       mojom::FeaturePolicyFeature,
       PolicyValue threshold_value,
       ReportOptions report_on_failure = ReportOptions::kDoNotReport,
-      const String& message = g_empty_string) const;
+      const String& message = g_empty_string,
+      const String& source_file = g_empty_string) const;
   FeatureEnabledState GetFeatureEnabledState(mojom::FeaturePolicyFeature) const;
   FeatureEnabledState GetFeatureEnabledState(mojom::FeaturePolicyFeature,
                                              PolicyValue threshold_value) const;
@@ -168,7 +170,8 @@
   virtual void ReportFeaturePolicyViolation(
       mojom::FeaturePolicyFeature,
       mojom::FeaturePolicyDisposition,
-      const String& message = g_empty_string) const {}
+      const String& message = g_empty_string,
+      const String& source_file = g_empty_string) const {}
 
  protected:
   SecurityContext();
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 141bb39..83e7fb42 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -99,7 +99,6 @@
     "location.cc",
     "location.h",
     "location_report_body.h",
-    "message_report_body.h",
     "navigation_rate_limiter.cc",
     "navigation_rate_limiter.h",
     "navigator.cc",
diff --git a/third_party/blink/renderer/core/frame/csp/csp_violation_report_body.h b/third_party/blink/renderer/core/frame/csp/csp_violation_report_body.h
index f693ab2..8573ec36 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_violation_report_body.h
+++ b/third_party/blink/renderer/core/frame/csp/csp_violation_report_body.h
@@ -21,9 +21,10 @@
   }
 
   CSPViolationReportBody(const SecurityPolicyViolationEventInit& violation_data)
-      : LocationReportBody(violation_data.sourceFile(),
-                           violation_data.lineNumber(),
-                           violation_data.columnNumber()),
+      : LocationReportBody(
+            SourceLocation::Capture(violation_data.sourceFile(),
+                                    violation_data.lineNumber(),
+                                    violation_data.columnNumber())),
         document_url_(violation_data.documentURI()),
         referrer_(violation_data.referrer()),
         blocked_url_(violation_data.blockedURI()),
diff --git a/third_party/blink/renderer/core/frame/deprecation_report_body.h b/third_party/blink/renderer/core/frame/deprecation_report_body.h
index 176a8e5..2029cd5 100644
--- a/third_party/blink/renderer/core/frame/deprecation_report_body.h
+++ b/third_party/blink/renderer/core/frame/deprecation_report_body.h
@@ -6,24 +6,23 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_DEPRECATION_REPORT_BODY_H_
 
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/core/frame/message_report_body.h"
+#include "third_party/blink/renderer/core/frame/location_report_body.h"
 
 namespace blink {
 
-class CORE_EXPORT DeprecationReportBody : public MessageReportBody {
+class CORE_EXPORT DeprecationReportBody : public LocationReportBody {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   DeprecationReportBody(const String& id,
                         double anticipatedRemoval,
                         const String& message)
-      : MessageReportBody(message),
-        id_(id),
-        anticipatedRemoval_(anticipatedRemoval) {}
+      : id_(id), message_(message), anticipatedRemoval_(anticipatedRemoval) {}
 
   ~DeprecationReportBody() override = default;
 
   String id() const { return id_; }
+  String message() const { return message_; }
   double anticipatedRemoval(bool& is_null) const {
     is_null = !anticipatedRemoval_;
     return anticipatedRemoval_;
@@ -31,6 +30,7 @@
 
  private:
   const String id_;
+  const String message_;
   const double anticipatedRemoval_;
 };
 
diff --git a/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h b/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
index d9880de4..430da4f6d 100644
--- a/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
+++ b/third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h
@@ -6,28 +6,39 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FEATURE_POLICY_VIOLATION_REPORT_BODY_H_
 
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/core/frame/message_report_body.h"
+#include "third_party/blink/renderer/core/frame/location_report_body.h"
 
 namespace blink {
 
-class CORE_EXPORT FeaturePolicyViolationReportBody : public MessageReportBody {
+class CORE_EXPORT FeaturePolicyViolationReportBody : public LocationReportBody {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   FeaturePolicyViolationReportBody(const String& feature_id,
                                    const String& message,
                                    const String& disposition)
-      : MessageReportBody(message),
+      : feature_id_(feature_id), message_(message), disposition_(disposition) {}
+
+  FeaturePolicyViolationReportBody(
+      const String& feature_id,
+      const String& message,
+      const String& disposition,
+      // url of the resource that violate the feature policy.
+      const String& resource_url)
+      : LocationReportBody(resource_url),
         feature_id_(feature_id),
+        message_(message),
         disposition_(disposition) {}
 
   String featureId() const { return feature_id_; }
   String disposition() const { return disposition_; }
+  String message() const { return message_; }
 
   ~FeaturePolicyViolationReportBody() override = default;
 
  private:
   const String feature_id_;
+  const String message_;
   const String disposition_;
 };
 
diff --git a/third_party/blink/renderer/core/frame/intervention_report_body.h b/third_party/blink/renderer/core/frame/intervention_report_body.h
index 0414005..873a319 100644
--- a/third_party/blink/renderer/core/frame/intervention_report_body.h
+++ b/third_party/blink/renderer/core/frame/intervention_report_body.h
@@ -6,23 +6,25 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_INTERVENTION_REPORT_BODY_H_
 
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/core/frame/message_report_body.h"
+#include "third_party/blink/renderer/core/frame/location_report_body.h"
 
 namespace blink {
 
-class CORE_EXPORT InterventionReportBody : public MessageReportBody {
+class CORE_EXPORT InterventionReportBody : public LocationReportBody {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   InterventionReportBody(const String& id, const String& message)
-      : MessageReportBody(message), id_(id) {}
+      : id_(id), message_(message) {}
 
   ~InterventionReportBody() override = default;
 
   String id() const { return id_; }
+  String message() const { return message_; }
 
  private:
   const String id_;
+  const String message_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/location_report_body.h b/third_party/blink/renderer/core/frame/location_report_body.h
index 9a730a55..5a87d761 100644
--- a/third_party/blink/renderer/core/frame/location_report_body.h
+++ b/third_party/blink/renderer/core/frame/location_report_body.h
@@ -16,32 +16,41 @@
 class LocationReportBody : public ReportBody {
  public:
   explicit LocationReportBody(std::unique_ptr<SourceLocation> location)
-      : location_(std::move(location)) {}
+      : source_file_(location->Url()),
+        line_number_(location->IsUnknown()
+                         ? base::nullopt
+                         : base::Optional<uint32_t>{location->LineNumber()}),
+        column_number_(location->IsUnknown() ? base::nullopt
+                                             : base::Optional<uint32_t>{
+                                                   location->ColumnNumber()}) {}
 
   LocationReportBody() : LocationReportBody(SourceLocation::Capture()) {}
 
   LocationReportBody(const String& source_file,
-                     unsigned line_number,
-                     unsigned column_number)
-      : LocationReportBody(
-            SourceLocation::Capture(source_file, line_number, column_number)) {}
+                     base::Optional<uint32_t> line_number = base::nullopt,
+                     base::Optional<uint32_t> column_number = base::nullopt)
+      : source_file_(source_file),
+        line_number_(line_number),
+        column_number_(column_number) {}
 
   ~LocationReportBody() override = default;
 
-  String sourceFile() const { return location_->Url(); }
+  String sourceFile() const { return source_file_; }
 
   uint32_t lineNumber(bool& is_null) const {
-    is_null = location_->IsUnknown();
-    return location_->LineNumber();
+    is_null = !line_number_.has_value();
+    return line_number_.value_or(0);
   }
 
   uint32_t columnNumber(bool& is_null) const {
-    is_null = location_->IsUnknown();
-    return location_->ColumnNumber();
+    is_null = !column_number_.has_value();
+    return column_number_.value_or(0);
   }
 
  protected:
-  std::unique_ptr<SourceLocation> location_;
+  const String source_file_;
+  base::Optional<uint32_t> line_number_;
+  base::Optional<uint32_t> column_number_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/message_report_body.h b/third_party/blink/renderer/core/frame/message_report_body.h
deleted file mode 100644
index a2398bc..0000000
--- a/third_party/blink/renderer/core/frame/message_report_body.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_MESSAGE_REPORT_BODY_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_MESSAGE_REPORT_BODY_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
-#include "third_party/blink/renderer/core/frame/location_report_body.h"
-
-namespace blink {
-
-class MessageReportBody : public LocationReportBody {
- public:
-  MessageReportBody(const String& message)
-      : LocationReportBody(), message_(message) {}
-
-  ~MessageReportBody() override = default;
-
-  String message() const { return message_; }
-
- protected:
-  const String message_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_MESSAGE_REPORT_BODY_H_
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 38b9a71e..43e0b10f 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -143,6 +143,65 @@
   }
 }
 
+bool FlexItem::UpdateAutoMarginsInCrossAxis(
+    LayoutUnit available_alignment_space) {
+  DCHECK(!box->IsOutOfFlowPositioned());
+  DCHECK_GE(available_alignment_space, LayoutUnit());
+
+  bool is_horizontal = algorithm->IsHorizontalFlow();
+  const Length& top_or_left = is_horizontal ? box->StyleRef().MarginTop()
+                                            : box->StyleRef().MarginLeft();
+  const Length& bottom_or_right = is_horizontal ? box->StyleRef().MarginBottom()
+                                                : box->StyleRef().MarginRight();
+  if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
+    desired_location.Move(LayoutUnit(), available_alignment_space / 2);
+    if (is_horizontal) {
+      box->SetMarginTop(available_alignment_space / 2);
+      box->SetMarginBottom(available_alignment_space / 2);
+    } else {
+      box->SetMarginLeft(available_alignment_space / 2);
+      box->SetMarginRight(available_alignment_space / 2);
+    }
+    return true;
+  }
+  bool should_adjust_top_or_left = true;
+  if (algorithm->IsColumnFlow() && !box->StyleRef().IsLeftToRightDirection()) {
+    // For column flows, only make this adjustment if topOrLeft corresponds to
+    // the "before" margin, so that flipForRightToLeftColumn will do the right
+    // thing.
+    should_adjust_top_or_left = false;
+  }
+  if (!algorithm->IsColumnFlow() &&
+      box->StyleRef().IsFlippedBlocksWritingMode()) {
+    // If we are a flipped writing mode, we need to adjust the opposite side.
+    // This is only needed for row flows because this only affects the
+    // block-direction axis.
+    should_adjust_top_or_left = false;
+  }
+
+  if (top_or_left.IsAuto()) {
+    if (should_adjust_top_or_left)
+      desired_location.Move(LayoutUnit(), available_alignment_space);
+
+    if (is_horizontal)
+      box->SetMarginTop(available_alignment_space);
+    else
+      box->SetMarginLeft(available_alignment_space);
+    return true;
+  }
+  if (bottom_or_right.IsAuto()) {
+    if (!should_adjust_top_or_left)
+      desired_location.Move(LayoutUnit(), available_alignment_space);
+
+    if (is_horizontal)
+      box->SetMarginBottom(available_alignment_space);
+    else
+      box->SetMarginRight(available_alignment_space);
+    return true;
+  }
+  return false;
+}
+
 void FlexItem::ComputeStretchedSize() {
   DCHECK_EQ(Alignment(), ItemPosition::kStretch);
   if (MainAxisIsInlineAxis() && box->StyleRef().LogicalHeight().IsAuto()) {
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index fdff3fe..123740b 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -124,6 +124,9 @@
   // it in cross_axis_size. DCHECKs if the item is not stretch aligned.
   void ComputeStretchedSize();
 
+  // Returns true if the margins were adjusted due to auto margin resolution.
+  bool UpdateAutoMarginsInCrossAxis(LayoutUnit available_alignment_space);
+
   inline const FlexLine* Line() const;
 
   FlexLayoutAlgorithm* algorithm;
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index 343b24a4..e60e7bc6 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -969,66 +969,6 @@
          child.StyleRef().MarginRight().IsAuto();
 }
 
-bool LayoutFlexibleBox::UpdateAutoMarginsInCrossAxis(
-    LayoutBox& child,
-    LayoutUnit available_alignment_space) {
-  DCHECK(!child.IsOutOfFlowPositioned());
-  DCHECK_GE(available_alignment_space, LayoutUnit());
-
-  bool is_horizontal = IsHorizontalFlow();
-  const Length& top_or_left = is_horizontal ? child.StyleRef().MarginTop()
-                                            : child.StyleRef().MarginLeft();
-  const Length& bottom_or_right = is_horizontal
-                                      ? child.StyleRef().MarginBottom()
-                                      : child.StyleRef().MarginRight();
-  if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
-    AdjustAlignmentForChild(child, available_alignment_space / 2);
-    if (is_horizontal) {
-      child.SetMarginTop(available_alignment_space / 2);
-      child.SetMarginBottom(available_alignment_space / 2);
-    } else {
-      child.SetMarginLeft(available_alignment_space / 2);
-      child.SetMarginRight(available_alignment_space / 2);
-    }
-    return true;
-  }
-  bool should_adjust_top_or_left = true;
-  if (IsColumnFlow() && !child.StyleRef().IsLeftToRightDirection()) {
-    // For column flows, only make this adjustment if topOrLeft corresponds to
-    // the "before" margin, so that flipForRightToLeftColumn will do the right
-    // thing.
-    should_adjust_top_or_left = false;
-  }
-  if (!IsColumnFlow() && child.StyleRef().IsFlippedBlocksWritingMode()) {
-    // If we are a flipped writing mode, we need to adjust the opposite side.
-    // This is only needed for row flows because this only affects the
-    // block-direction axis.
-    should_adjust_top_or_left = false;
-  }
-
-  if (top_or_left.IsAuto()) {
-    if (should_adjust_top_or_left)
-      AdjustAlignmentForChild(child, available_alignment_space);
-
-    if (is_horizontal)
-      child.SetMarginTop(available_alignment_space);
-    else
-      child.SetMarginLeft(available_alignment_space);
-    return true;
-  }
-  if (bottom_or_right.IsAuto()) {
-    if (!should_adjust_top_or_left)
-      AdjustAlignmentForChild(child, available_alignment_space);
-
-    if (is_horizontal)
-      child.SetMarginBottom(available_alignment_space);
-    else
-      child.SetMarginRight(available_alignment_space);
-    return true;
-  }
-  return false;
-}
-
 LayoutUnit LayoutFlexibleBox::ComputeChildMarginValue(const Length& margin) {
   // When resolving the margins, we use the content size for resolving percent
   // and calc (for percents in calc expressions) margins. Fortunately, percent
@@ -1617,10 +1557,11 @@
     for (FlexItem& flex_item : line_context.line_items) {
       DCHECK(!flex_item.box->IsOutOfFlowPositioned());
 
-      if (UpdateAutoMarginsInCrossAxis(
-              *flex_item.box,
-              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace())))
+      if (flex_item.UpdateAutoMarginsInCrossAxis(
+              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace()))) {
+        ResetAlignmentForChild(*flex_item.box, flex_item.desired_location.Y());
         continue;
+      }
 
       ItemPosition position = flex_item.Alignment();
       if (position == ItemPosition::kStretch) {
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h
index 1509429..47977523 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -172,9 +172,6 @@
 
   void LayoutFlexItems(bool relayout_children, SubtreeLayoutScope&);
   bool HasAutoMarginsInCrossAxis(const LayoutBox& child) const;
-  // Returns true if either of cross axis margins is non-auto.
-  bool UpdateAutoMarginsInCrossAxis(LayoutBox& child,
-                                    LayoutUnit available_alignment_space);
   void RepositionLogicalHeightDependentFlexItems(
       FlexLayoutAlgorithm& algorithm);
   LayoutUnit ClientLogicalBottomAfterRepositioning();
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index ac1eed1..e2c4901a 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -419,12 +419,7 @@
 void LayoutImage::UpdateAfterLayout() {
   LayoutBox::UpdateAfterLayout();
   Node* node = GetNode();
-
-  // Check for oversized-images policy.
-  // TODO(loonybear): Support oversized-images policy on other image types
-  // in addition to HTMLImageElement.
   if (auto* image_element = ToHTMLImageElementOrNull(node)) {
-    // Report violation of unsized-media policy.
     media_element_parser_helpers::ReportUnsizedMediaViolation(
         this, image_element->IsDefaultIntrinsicSize());
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h b/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
index 81858b1e..b3d84836 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
@@ -46,9 +46,11 @@
   // in the next fragmentainer. In this case we create a break token for a node
   // that hasn't yet produced any fragments.
   static scoped_refptr<NGBlockBreakToken> CreateBreakBefore(
-      NGLayoutInputNode node) {
+      NGLayoutInputNode node,
+      bool is_forced_break) {
     auto* token = new NGBlockBreakToken(node);
     token->is_break_before_ = true;
+    token->is_forced_break_ = is_forced_break;
     return base::AdoptRef(token);
   }
 
@@ -72,6 +74,8 @@
   // one it was it was first encountered, due to block space shortage.
   bool IsBreakBefore() const { return is_break_before_; }
 
+  bool IsForcedBreak() const { return is_forced_break_; }
+
   bool HasLastResortBreak() const { return has_last_resort_break_; }
 
   // Return true if all children have been "seen". When we have reached this
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index d44ae2d6..2e0e88d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1628,14 +1628,26 @@
 
   // Calculate margins in parent's writing mode.
   bool margins_fully_resolved;
-  NGBoxStrut margins = CalculateMargins(child, is_new_fc, child_break_token,
-                                        &margins_fully_resolved);
+  NGBoxStrut margins =
+      CalculateMargins(child, is_new_fc, &margins_fully_resolved);
 
   // Append the current margin strut with child's block start margin.
   // Non empty border/padding, and new formatting-context use cases are handled
   // inside of the child's layout
   NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
 
+  const auto* child_block_break_token =
+      DynamicTo<NGBlockBreakToken>(child_break_token);
+  bool is_resuming_after_break = IsResumingLayout(child_block_break_token);
+  if (child_block_break_token && child_block_break_token->IsForcedBreak()) {
+    // Margins after a fragmentainer break are usually discarded, but not if
+    // there's a forced break.
+    margin_strut = NGMarginStrut();
+  } else if (is_resuming_after_break) {
+    // We're past the block-start edge of this child. Don't repeat the margin.
+    margins.block_start = LayoutUnit();
+  }
+
   LayoutUnit logical_block_offset =
       previous_inflow_position.logical_block_offset;
 
@@ -1671,7 +1683,8 @@
           margins.LineLeft(ConstraintSpace().Direction()),
       BfcBlockOffset() + logical_block_offset};
 
-  return {child_bfc_offset, margin_strut, margins, margins_fully_resolved};
+  return {child_bfc_offset, margin_strut, margins, margins_fully_resolved,
+          is_resuming_after_break};
 }
 
 NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
@@ -2026,7 +2039,7 @@
       space_available.ClampNegativeToZero();
   // Drop the fragment on the floor and retry at the start of the next
   // fragmentainer.
-  container_builder_.AddBreakBeforeChild(child);
+  container_builder_.AddBreakBeforeChild(child, break_type == ForcedBreak);
   container_builder_.SetDidBreak();
   if (break_type == ForcedBreak) {
     container_builder_.SetHasForcedBreak();
@@ -2121,7 +2134,6 @@
 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
     NGLayoutInputNode child,
     bool is_new_fc,
-    const NGBreakToken* child_break_token,
     bool* margins_fully_resolved) {
   // We need to at least partially resolve margins before creating a constraint
   // space for layout. Layout needs to know the line-left offset before
@@ -2145,8 +2157,6 @@
   NGBoxStrut margins = ComputeMarginsFor(
       child_style, child_percentage_size_.inline_size,
       ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction());
-  if (ShouldIgnoreBlockStartMargin(ConstraintSpace(), child, child_break_token))
-    margins.block_start = LayoutUnit();
 
   // As long as the child isn't establishing a new formatting context, we need
   // to know its line-left offset before layout, to be able to position child
@@ -2214,9 +2224,6 @@
   if (NGBaseline::ShouldPropagateBaselines(child))
     builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
 
-  builder.SetBfcOffset(child_data.bfc_offset_estimate);
-  builder.SetMarginStrut(child_data.margin_strut);
-
   bool has_bfc_block_offset = container_builder_.BfcBlockOffset().has_value();
 
   // Propagate the |NGConstraintSpace::ForcedBfcBlockOffset| down to our
@@ -2285,11 +2292,18 @@
   builder.SetClearanceOffset(clearance_offset);
 
   if (!is_new_fc) {
+    builder.SetMarginStrut(child_data.margin_strut);
+    builder.SetBfcOffset(child_data.bfc_offset_estimate);
     builder.SetExclusionSpace(exclusion_space_);
     if (!has_bfc_block_offset) {
       builder.SetAdjoiningObjectTypes(
           container_builder_.AdjoiningObjectTypes());
     }
+  } else if (child_data.is_resuming_after_break) {
+    // If the child is being resumed after a break, margins inside the child may
+    // be adjoining with the fragmentainer boundary, regardless of whether the
+    // child establishes a new formatting context or not.
+    builder.SetDiscardingMarginStrut();
   }
 
   if (ConstraintSpace().HasBlockFragmentation()) {
@@ -2419,17 +2433,27 @@
   if (NeedsAbortOnBfcBlockOffsetChange())
     return false;
 
-  // Reset the previous inflow position. Clear the margin strut and set the
-  // offset to our block-start border edge.
-  //
-  // We'll now end up at the block-start border edge. If the BFC block offset
-  // was resolved due to a block-start border or padding, that must be added by
-  // the caller, for subsequent layout to continue at the right position.
-  // Whether we need to add border+padding or not isn't something we should
-  // determine here, so it must be dealt with as part of initializing the
-  // layout algorithm.
+  // Set the offset to our block-start border edge. We'll now end up at the
+  // block-start border edge. If the BFC block offset was resolved due to a
+  // block-start border or padding, that must be added by the caller, for
+  // subsequent layout to continue at the right position. Whether we need to add
+  // border+padding or not isn't something we should determine here, so it must
+  // be dealt with as part of initializing the layout algorithm.
   previous_inflow_position->logical_block_offset = LayoutUnit();
-  previous_inflow_position->margin_strut = NGMarginStrut();
+
+  // Resolving the BFC offset normally means that we have finished collapsing
+  // adjoining margins, so that we can reset the margin strut. One exception
+  // here is if we're resuming after a break, in which case we know that we can
+  // resolve the BFC offset to the block-start of the fragmentainer
+  // (block-offset 0). But keep the margin strut, since we're essentially still
+  // collapsing with the fragmentainer boundary, which will eat / discard all
+  // adjoining margins - unless this is at a forced break. DCHECK that the strut
+  // is empty (note that a strut that's set up to eat all margins will also be
+  // considered to be empty).
+  if (!is_resuming_)
+    previous_inflow_position->margin_strut = NGMarginStrut();
+  else
+    DCHECK(previous_inflow_position->margin_strut.IsEmpty());
 
   return true;
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index 8101231..e3177c18 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -39,6 +39,7 @@
   NGMarginStrut margin_strut;
   NGBoxStrut margins;
   bool margins_fully_resolved;
+  bool is_resuming_after_break;
 };
 
 // A class for general block layout (e.g. a <div> with no special style).
@@ -90,7 +91,6 @@
 
   NGBoxStrut CalculateMargins(NGLayoutInputNode child,
                               bool is_new_fc,
-                              const NGBreakToken* child_break_token,
                               bool* margins_fully_resolved);
 
   // Creates a new constraint space for the current child.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 481bca1..f12c374 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -85,7 +85,8 @@
   children_.resize(0);
 }
 
-void NGBoxFragmentBuilder::AddBreakBeforeChild(NGLayoutInputNode child) {
+void NGBoxFragmentBuilder::AddBreakBeforeChild(NGLayoutInputNode child,
+                                               bool is_forced_break) {
   DCHECK(has_block_fragmentation_);
   if (auto* child_inline_node = DynamicTo<NGInlineNode>(child)) {
     if (inline_break_tokens_.IsEmpty()) {
@@ -100,7 +101,7 @@
     }
     return;
   }
-  auto token = NGBlockBreakToken::CreateBreakBefore(child);
+  auto token = NGBlockBreakToken::CreateBreakBefore(child, is_forced_break);
   child_break_tokens_.push_back(token);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 11c0e028..7674ccf 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -89,7 +89,7 @@
   // Add a break token for a child that doesn't yet have any fragments, because
   // its first fragment is to be produced in the next fragmentainer. This will
   // add a break token for the child, but no fragment.
-  void AddBreakBeforeChild(NGLayoutInputNode child);
+  void AddBreakBeforeChild(NGLayoutInputNode child, bool is_forced_break);
 
   // Prepare for a break token before the specified line.
   void AddBreakBeforeLine(int line_number);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_break_token.h b/third_party/blink/renderer/core/layout/ng/ng_break_token.h
index 10f548a7..d673d357 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_break_token.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_break_token.h
@@ -98,6 +98,8 @@
 
   unsigned is_break_before_ : 1;
 
+  unsigned is_forced_break_ : 1;
+
   // We're attempting to break at an undesirable place. Sometimes that's
   // unavoidable, but we should only break here if we cannot find a better break
   // point further up in the ancestry.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index fc9b4eef..5f38663 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -150,13 +150,14 @@
     // balancing).
     LayoutUnit minimal_space_shortage(LayoutUnit::Max());
 
-    // Allow any block-start margins at the start of the first column.
-    bool separate_leading_margins = true;
-
     do {
+      // This is the first column in this fragmentation context if there are no
+      // preceding columns in this row and there are also no preceding rows.
+      bool is_first_fragmentainer = !break_token && !BreakToken();
+
       // Lay out one column. Each column will become a fragment.
       NGConstraintSpace child_space = CreateConstraintSpaceForColumns(
-          column_size, separate_leading_margins, balance_columns);
+          column_size, is_first_fragmentainer, balance_columns);
 
       NGFragmentGeometry fragment_geometry =
           CalculateInitialFragmentGeometry(child_space, Node());
@@ -176,12 +177,8 @@
             std::min(minimal_space_shortage, space_shortage);
       }
       actual_column_count++;
-      if (result->HasForcedBreak()) {
+      if (result->HasForcedBreak())
         forced_break_count++;
-        separate_leading_margins = true;
-      } else {
-        separate_leading_margins = false;
-      }
 
       LayoutUnit block_size = NGFragment(writing_mode, column).BlockSize();
       intrinsic_block_size =
@@ -426,7 +423,7 @@
 
 NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForColumns(
     const LogicalSize& column_size,
-    bool separate_leading_margins,
+    bool is_first_fragmentainer,
     bool balance_columns) const {
   NGConstraintSpaceBuilder space_builder(
       ConstraintSpace(), Style().GetWritingMode(), /* is_new_fc */ true);
@@ -446,10 +443,15 @@
   space_builder.SetFragmentainerBlockSize(column_block_size);
   space_builder.SetFragmentainerSpaceAtBfcStart(column_block_size);
   space_builder.SetIsAnonymous(true);
-  space_builder.SetSeparateLeadingFragmentainerMargins(
-      separate_leading_margins);
   if (balance_columns)
     space_builder.SetIsInsideBalancedColumns();
+  if (!is_first_fragmentainer) {
+    // Margins at fragmentainer boundaries should be eaten and truncated to
+    // zero. Note that this doesn't apply to margins at forced breaks, but we'll
+    // deal with those when we get to them. Set up a margin strut that eats all
+    // leading adjacent margins.
+    space_builder.SetDiscardingMarginStrut();
+  }
 
   return space_builder.ToConstraintSpace();
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index 310551e..46b9b3e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -44,7 +44,7 @@
 
   NGConstraintSpace CreateConstraintSpaceForColumns(
       const LogicalSize& column_size,
-      bool separate_leading_margins,
+      bool is_first_fragmentainer,
       bool balance_columns) const;
   NGConstraintSpace CreateConstraintSpaceForBalancing(
       const LogicalSize& column_size) const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index 9d25c79..0fb2284 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -2030,6 +2030,91 @@
   EXPECT_EQ(expectation, dump);
 }
 
+TEST_F(NGColumnLayoutAlgorithmTest, ForcedAndUnforcedBreaksAtSameBoundary) {
+  // We have two parallel flows, one with a forced break inside and one with an
+  // unforced break. Check that we handle the block-start margins correctly
+  // (i.e. truncate at unforced breaks but not at forced breaks).
+  //
+  // Note about the #blockchildifier DIV in the test: it's there to force block
+  // layout, as our fragmentation support for floats inside an inline formatting
+  // context is borked; see crbug.com/915929
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #parent {
+        columns: 3;
+        column-fill: auto;
+        column-gap: 10px;
+        width: 320px;
+        height: 100px;
+      }
+    </style>
+    <div id="container">
+      <div id="parent">
+        <div id="blockchildifier"></div>
+        <div style="float:left; width:33px;">
+          <div style="width:10px; height:70px;"></div>
+          <div style="break-before:column; margin-top:50px; width:20px; height:20px;"></div>
+       </div>
+       <div style="float:left; width:34px;">
+         <div style="width:10px; height:70px;"></div>
+        <div style="margin-top:50px; width:20px; height:20px;"></div>
+      </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:100x0
+        offset:0,0 size:33x100
+          offset:0,0 size:10x70
+        offset:33,0 size:34x100
+          offset:0,0 size:10x70
+      offset:110,0 size:100x70
+        offset:0,0 size:33x70
+          offset:0,50 size:20x20
+        offset:33,0 size:34x20
+          offset:0,0 size:20x20
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGColumnLayoutAlgorithmTest, ResumeInsideFormattingContextRoot) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #parent {
+        columns: 3;
+        column-fill: auto;
+        column-gap: 10px;
+        width: 320px;
+        height: 100px;
+      }
+    </style>
+    <div id="container">
+      <div id="parent">
+        <div style="display:flow-root; width:33px;">
+          <div style="width:10px; height:70px;"></div>
+          <div style="margin-top:50px; width:20px; height:20px;"></div>
+       </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:33x100
+          offset:0,0 size:10x70
+      offset:110,0 size:100x20
+        offset:0,0 size:33x20
+          offset:0,0 size:20x20
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 TEST_F(NGColumnLayoutAlgorithmTest, MinMax) {
   // The multicol container here contains two inline-blocks with a line break
   // opportunity between them. We'll test what min/max values we get for the
@@ -2887,9 +2972,9 @@
       offset:0,0 size:100x100
         offset:0,0 size:50x70
         offset:0,70 size:100x20
-      offset:110,0 size:100x22
-        offset:0,0 size:57x22
-          offset:1,1 size:44x20
+      offset:110,0 size:100x41
+        offset:0,0 size:57x41
+          offset:1,20 size:44x20
             offset:0,0 size:33x20
 )DUMP";
   EXPECT_EQ(expectation, dump);
@@ -2985,6 +3070,43 @@
   EXPECT_EQ(expectation, dump);
 }
 
+TEST_F(NGColumnLayoutAlgorithmTest, NestedWithEdibleMargin) {
+  // There's a block-start margin after an unforced break. It should be eaten by
+  // the fragmentainer boundary.
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .outer { columns:3; height:50px; column-fill:auto; width:320px; }
+      .inner { columns:2; height:100px; column-fill:auto; }
+      .outer, .inner { column-gap:10px; }
+    </style>
+    <div id="container">
+      <div class="outer">
+        <div class="inner">
+          <div style="width:5px; height:80px;"></div>
+          <div style="break-inside:avoid; margin-top:30px; width:10px; height:10px;"></div>
+        </div>
+      </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x50
+    offset:0,0 size:320x50
+      offset:0,0 size:100x50
+        offset:0,0 size:100x50
+          offset:0,0 size:45x50
+            offset:0,0 size:5x50
+          offset:55,0 size:45x50
+            offset:0,0 size:5x30
+      offset:110,0 size:100x50
+        offset:0,0 size:100x50
+          offset:0,0 size:45x10
+            offset:0,0 size:10x10
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 TEST_F(NGColumnLayoutAlgorithmTest, NestedLimitedHeight) {
   // This tests that we don't advance to the next outer fragmentainer when we've
   // reached the bottom of an inner multicol container. We should create inner
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 6a5a40d0..4df04c9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -268,16 +268,6 @@
     return bitfields_.is_new_formatting_context;
   }
 
-  // Return true if we are to separate (i.e. honor, rather than collapse)
-  // block-start margins at the beginning of fragmentainers. This only makes a
-  // difference if we're block-fragmented (pagination, multicol, etc.). Then
-  // block-start margins at the beginning of a fragmentainers are to be
-  // truncated to 0 if they occur after a soft (unforced) break.
-  bool HasSeparateLeadingFragmentainerMargins() const {
-    return HasRareData() &&
-           rare_data_->has_separate_leading_fragmentainer_margins;
-  }
-
   // Whether the current node is a table-cell.
   bool IsTableCell() const { return bitfields_.is_table_cell; }
 
@@ -557,7 +547,6 @@
         : bfc_offset(bfc_offset),
           block_direction_fragmentation_type(
               static_cast<unsigned>(kFragmentNone)),
-          has_separate_leading_fragmentainer_margins(false),
           is_inside_balanced_columns(false) {}
     RareData(const RareData&) = default;
     ~RareData() = default;
@@ -579,7 +568,6 @@
     LayoutUnit fragmentainer_space_at_bfc_start = kIndefiniteSize;
 
     unsigned block_direction_fragmentation_type : 2;
-    unsigned has_separate_leading_fragmentainer_margins : 1;
     unsigned is_inside_balanced_columns : 1;
 
     bool MaySkipLayout(const RareData& other) const {
@@ -593,8 +581,6 @@
                  other.fragmentainer_space_at_bfc_start &&
              block_direction_fragmentation_type ==
                  other.block_direction_fragmentation_type &&
-             has_separate_leading_fragmentainer_margins ==
-                 other.has_separate_leading_fragmentainer_margins &&
              is_inside_balanced_columns == other.is_inside_balanced_columns;
     }
 
@@ -607,7 +593,6 @@
              fragmentainer_block_size == kIndefiniteSize &&
              fragmentainer_space_at_bfc_start == kIndefiniteSize &&
              block_direction_fragmentation_type == kFragmentNone &&
-             !has_separate_leading_fragmentainer_margins &&
              !is_inside_balanced_columns;
     }
   };
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 84bfd8e..57d44625 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -167,15 +167,6 @@
     space_.EnsureRareData()->is_inside_balanced_columns = true;
   }
 
-  void SetSeparateLeadingFragmentainerMargins(bool b) {
-#if DCHECK_IS_ON()
-    DCHECK(!has_separate_leading_fragmentainer_margins_set_);
-    has_separate_leading_fragmentainer_margins_set_ = true;
-#endif
-    if (b)
-      space_.EnsureRareData()->has_separate_leading_fragmentainer_margins = b;
-  }
-
   void SetIsTableCell(bool b) { space_.bitfields_.is_table_cell = b; }
 
   void SetIsRestrictedBlockSizeTableCell(bool b) {
@@ -209,6 +200,18 @@
       space_.EnsureRareData()->margin_strut = margin_strut;
   }
 
+  // Set up a margin strut that discards all adjoining margins. This is used to
+  // discard block-start margins after fragmentainer breaks.
+  void SetDiscardingMarginStrut() {
+#if DCHECK_IS_ON()
+    DCHECK(!is_margin_strut_set_);
+    is_margin_strut_set_ = true;
+#endif
+    NGMarginStrut discarding_margin_strut;
+    discarding_margin_strut.discard_margins = true;
+    space_.EnsureRareData()->margin_strut = discarding_margin_strut;
+  }
+
   void SetBfcOffset(const NGBfcOffset& bfc_offset) {
     if (!is_new_fc_) {
       if (space_.HasRareData())
@@ -328,7 +331,6 @@
   bool is_fragmentainer_block_size_set_ = false;
   bool is_fragmentainer_space_at_bfc_start_set_ = false;
   bool is_block_direction_fragmentation_type_set_ = false;
-  bool has_separate_leading_fragmentainer_margins_set_ = false;
   bool is_margin_strut_set_ = false;
   bool is_optimistic_bfc_block_offset_set_ = false;
   bool is_forced_bfc_block_offset_set_ = false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index 829a2cc7..50a79fe 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -481,11 +481,12 @@
     for (wtf_size_t child_number = 0;
          child_number < line_context.line_items.size(); ++child_number) {
       FlexItem& flex_item = line_context.line_items[child_number];
-      // TODO(dgrogan): Make this obey the rule that the item stretches only if
-      // neither of the cross-axis margins are auto from
-      // https://drafts.csswg.org/css-flexbox/#valdef-align-items-stretch
-      // Just use DoesItemStretch here?
-      if (flex_item.Alignment() == ItemPosition::kStretch) {
+
+      // UpdateAutoMarginsInCrossAxis updates the flex_item's desired_location
+      // if the auto margins have an effect.
+      if (!flex_item.UpdateAutoMarginsInCrossAxis(
+              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace())) &&
+          flex_item.Alignment() == ItemPosition::kStretch) {
         flex_item.ComputeStretchedSize();
 
         WritingMode child_writing_mode =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
index ef8c1cc..6352e5f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -67,7 +67,8 @@
     const NGUnpositionedFloat& unpositioned_float,
     const NGConstraintSpace& parent_space,
     const ComputedStyle& parent_style,
-    base::Optional<LayoutUnit> origin_block_offset = base::nullopt) {
+    base::Optional<LayoutUnit> origin_block_offset = base::nullopt,
+    bool is_resuming_after_break = false) {
   const ComputedStyle& style = unpositioned_float.node.Style();
   NGConstraintSpaceBuilder builder(parent_space, style.GetWritingMode(),
                                    /* is_new_fc */ true);
@@ -83,6 +84,12 @@
     builder.SetFragmentationType(NGFragmentationType::kFragmentNone);
   }
 
+  // If we're resuming layout of this float after a fragmentainer break, the
+  // margins of its children may be adjoining with the fragmentainer
+  // block-start, in which case they may get truncated.
+  if (is_resuming_after_break)
+    builder.SetDiscardingMarginStrut();
+
   builder.SetAvailableSize(float_available_size);
   builder.SetPercentageResolutionSize(float_percentage_size);
   builder.SetReplacedPercentageResolutionSize(float_replaced_percentage_size);
@@ -246,19 +253,17 @@
     layout_result = unpositioned_float->layout_result;
     fragment_margins = unpositioned_float->margins;
   } else {
+    bool is_resuming_after_break =
+        IsResumingLayout(unpositioned_float->token.get());
     NGConstraintSpace space = CreateConstraintSpaceForFloat(
         float_available_size, float_percentage_size,
         float_replaced_percentage_size, *unpositioned_float, parent_space,
-        parent_style, origin_bfc_offset.block_offset);
+        parent_style, origin_bfc_offset.block_offset, is_resuming_after_break);
     layout_result =
         unpositioned_float->node.Layout(space, unpositioned_float->token.get());
     fragment_margins = ComputeMarginsFor(
         space, unpositioned_float->node.Style(), parent_space);
 
-    // Make the margins fragmentation aware.
-    if (ShouldIgnoreBlockStartMargin(parent_space, unpositioned_float->node,
-                                     unpositioned_float->token.get()))
-      fragment_margins.block_start = LayoutUnit();
     if (const NGBreakToken* break_token =
             layout_result->PhysicalFragment().BreakToken())
       fragment_margins.block_end = LayoutUnit();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 6e8d97a..04cadc8b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -72,30 +72,6 @@
   return false;
 }
 
-bool ShouldIgnoreBlockStartMargin(const NGConstraintSpace& constraint_space,
-                                  NGLayoutInputNode child,
-                                  const NGBreakToken* child_break_token) {
-  // Always ignore margins if we're not at the start of the child.
-  auto* child_block_break_token =
-      DynamicTo<NGBlockBreakToken>(child_break_token);
-  if (child_block_break_token && !child_block_break_token->IsBreakBefore())
-    return true;
-
-  // If we're not fragmented or have been explicitly instructed to honor
-  // margins, don't ignore them.
-  if (!constraint_space.HasBlockFragmentation() ||
-      constraint_space.HasSeparateLeadingFragmentainerMargins())
-    return false;
-
-  // Only ignore margins if we're at the start of the fragmentainer.
-  if (constraint_space.FragmentainerBlockSize() !=
-      constraint_space.FragmentainerSpaceAtBfcStart())
-    return false;
-
-  // Otherwise, only ignore in-flow margins.
-  return !child.IsFloating() && !child.IsOutOfFlowPositioned();
-}
-
 void SetupFragmentation(const NGConstraintSpace& parent_space,
                         LayoutUnit new_bfc_block_offset,
                         NGConstraintSpaceBuilder* builder) {
@@ -104,12 +80,6 @@
   LayoutUnit space_available =
       parent_space.FragmentainerSpaceAtBfcStart() - new_bfc_block_offset;
 
-  // The policy regarding collapsing block-start margin with the fragmentainer
-  // block-start is the same throughout the entire fragmentainer (although it
-  // really only matters at the beginning of each fragmentainer, we don't need
-  // to bother to check whether we're actually at the start).
-  builder->SetSeparateLeadingFragmentainerMargins(
-      parent_space.HasSeparateLeadingFragmentainerMargins());
   builder->SetFragmentainerBlockSize(parent_space.FragmentainerBlockSize());
   builder->SetFragmentainerSpaceAtBfcStart(space_available);
   builder->SetFragmentationType(parent_space.BlockFragmentationType());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index 3812d1f4..459f9e3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -32,14 +32,6 @@
 // current fragmentation context.
 bool IsForcedBreakValue(const NGConstraintSpace&, EBreakBetween);
 
-// Return true if we are to ignore the block-start margin of the child. At the
-// start of fragmentainers, in-flow block-start margins are ignored, unless
-// we're right after a forced break.
-// https://drafts.csswg.org/css-break/#break-margins
-bool ShouldIgnoreBlockStartMargin(const NGConstraintSpace&,
-                                  NGLayoutInputNode,
-                                  const NGBreakToken*);
-
 // Return true if we're resuming layout after a previous break.
 inline bool IsResumingLayout(const NGBlockBreakToken* token) {
   return token && !token->IsBreakBefore();
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index dc6f000..e03c5fa 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -540,20 +540,27 @@
     UMA_HISTOGRAM_ENUMERATION("Blink.UseCounter.FeaturePolicy.ImageFormats",
                               compression_format);
   }
+
+  // Pass image url to reporting API.
+  const String& image_url = Url().GetString();
+
   if (compression_format == ImageDecoder::kLossyFormat) {
     // Enforce the lossy image policy.
     return context.IsFeatureEnabled(
         mojom::FeaturePolicyFeature::kUnoptimizedLossyImages,
-        PolicyValue(compression_ratio_1k), ReportOptions::kReportOnFailure);
+        PolicyValue(compression_ratio_1k), ReportOptions::kReportOnFailure,
+        g_empty_string, image_url);
   }
   if (compression_format == ImageDecoder::kLosslessFormat) {
     // Enforce the lossless image policy.
     bool enabled_by_10k_policy = context.IsFeatureEnabled(
         mojom::FeaturePolicyFeature::kUnoptimizedLosslessImages,
-        PolicyValue(compression_ratio_10k), ReportOptions::kReportOnFailure);
+        PolicyValue(compression_ratio_10k), ReportOptions::kReportOnFailure,
+        g_empty_string, image_url);
     bool enabled_by_1k_policy = context.IsFeatureEnabled(
         mojom::FeaturePolicyFeature::kUnoptimizedLosslessImagesStrict,
-        PolicyValue(compression_ratio_1k), ReportOptions::kReportOnFailure);
+        PolicyValue(compression_ratio_1k), ReportOptions::kReportOnFailure,
+        g_empty_string, image_url);
     return enabled_by_10k_policy && enabled_by_1k_policy;
   }
 
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc
index 3dd4ee5..fcb1e5a 100644
--- a/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -51,12 +51,19 @@
       image_size.Width() / (dpr * layout_size.Width());
   double downscale_ratio_height =
       image_size.Height() / (dpr * layout_size.Height());
+
+  const LayoutImageResource* image_resource = layout_image.ImageResource();
+  const ImageResourceContent* cached_image =
+      image_resource ? image_resource->CachedImage() : nullptr;
+  const String& image_url =
+      cached_image ? cached_image->Url().GetString() : g_empty_string;
+
   return !layout_image.GetDocument().IsFeatureEnabled(
       mojom::FeaturePolicyFeature::kOversizedImages,
       blink::PolicyValue(
           std::max(downscale_ratio_width, downscale_ratio_height),
           blink::mojom::PolicyValueType::kDecDouble),
-      ReportOptions::kReportOnFailure);
+      ReportOptions::kReportOnFailure, g_empty_string, image_url);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/devtools/front_end/browser_debugger/domBreakpointsSidebarPane.css b/third_party/blink/renderer/devtools/front_end/browser_debugger/domBreakpointsSidebarPane.css
index e58d8201..d5622c2 100644
--- a/third_party/blink/renderer/devtools/front_end/browser_debugger/domBreakpointsSidebarPane.css
+++ b/third_party/blink/renderer/devtools/front_end/browser_debugger/domBreakpointsSidebarPane.css
@@ -27,6 +27,7 @@
 
 .breakpoint-hit {
     background-color: rgb(255, 255, 194);
+    border-right: 3px solid rgb(107, 97, 48);
 }
 
 :host-context(.-theme-with-dark-background) .breakpoint-hit {
diff --git a/third_party/blink/renderer/devtools/front_end/browser_debugger/eventListenerBreakpoints.css b/third_party/blink/renderer/devtools/front_end/browser_debugger/eventListenerBreakpoints.css
index fe842e2..abc51e44c 100644
--- a/third_party/blink/renderer/devtools/front_end/browser_debugger/eventListenerBreakpoints.css
+++ b/third_party/blink/renderer/devtools/front_end/browser_debugger/eventListenerBreakpoints.css
@@ -39,6 +39,7 @@
 
 .breakpoint-hit .breakpoint-hit-marker {
     background-color: rgb(255, 255, 194);
+    border-right: 3px solid rgb(107, 97, 48);
     height: 18px;
     left: 0;
     margin-left: -30px;
@@ -46,3 +47,8 @@
     right: -4px;
     z-index: -1;
 }
+
+:host-context(.-theme-with-dark-background) .breakpoint-hit .breakpoint-hit-marker {
+    background-color: hsl(46, 98%, 22%);
+}
+
diff --git a/third_party/blink/renderer/devtools/front_end/browser_debugger/xhrBreakpointsSidebarPane.css b/third_party/blink/renderer/devtools/front_end/browser_debugger/xhrBreakpointsSidebarPane.css
index 317bf57..03dad81a 100644
--- a/third_party/blink/renderer/devtools/front_end/browser_debugger/xhrBreakpointsSidebarPane.css
+++ b/third_party/blink/renderer/devtools/front_end/browser_debugger/xhrBreakpointsSidebarPane.css
@@ -44,6 +44,7 @@
 
 .breakpoint-hit {
     background-color: rgb(255, 255, 194);
+    border-right: 3px solid rgb(107, 97, 48);
 }
 
 :host-context(.-theme-with-dark-background) .breakpoint-hit {
diff --git a/third_party/blink/renderer/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css b/third_party/blink/renderer/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css
index 8a2f7817..7cf2a2d 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css
+++ b/third_party/blink/renderer/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css
@@ -35,6 +35,7 @@
 
 .breakpoint-hit {
     background-color: rgb(255, 255, 194);
+    border-right: 3px solid rgb(107, 97, 48);
 }
 
 :host-context(.-theme-with-dark-background) .breakpoint-hit {
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
index 001cd2b1..9c1f09f 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
@@ -189,9 +189,9 @@
     LOG(ERROR) << "OnNetworkRouteChanged called, but ICE transport released";
     return;
   }
-  const cricket::CandidatePairInterface* selected_connection =
-      ice_transport_channel()->selected_connection();
-  if (!selected_connection) {
+  const absl::optional<const cricket::CandidatePair> selected_pair =
+      ice_transport_channel()->GetSelectedCandidatePair();
+  if (!selected_pair) {
     // The selected connection will only be null if the ICE connection has
     // totally failed, at which point we'll get a StateChanged signal. The
     // client will implicitly clear the selected candidate pair when it receives
@@ -199,9 +199,8 @@
     // here.
     return;
   }
-  delegate_->OnSelectedCandidatePairChanged(
-      std::make_pair(selected_connection->local_candidate(),
-                     selected_connection->remote_candidate()));
+  delegate_->OnSelectedCandidatePairChanged(std::make_pair(
+      selected_pair->local_candidate(), selected_pair->remote_candidate()));
 }
 
 static const char* IceRoleToString(cricket::IceRole role) {
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl
index 8e17e13..d1869d2 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -24,5 +24,5 @@
   [SameObject] readonly attribute XRSpace targetRaySpace;
   [SameObject] readonly attribute XRSpace? gripSpace;
   [SameObject, Measure] readonly attribute Gamepad? gamepad;
-  [SameObject] readonly attribute FrozenArray<DOMString> profiles;
+  [SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> profiles;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl b/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl
index 69c630d9..3d3acfa 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_sources_change_event.idl
@@ -9,6 +9,6 @@
     Constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict)
 ] interface XRInputSourcesChangeEvent : Event {
   [SameObject] readonly attribute XRSession session;
-  [SameObject] readonly attribute FrozenArray<XRInputSource> added;
-  [SameObject] readonly attribute FrozenArray<XRInputSource> removed;
+  [SameObject, SaveSameObject] readonly attribute FrozenArray<XRInputSource> added;
+  [SameObject, SaveSameObject] readonly attribute FrozenArray<XRInputSource> removed;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl b/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl
index ecff9175..dae4e998 100644
--- a/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl
+++ b/third_party/blink/renderer/modules/xr/xr_viewer_pose.idl
@@ -8,5 +8,5 @@
     Exposed=Window,
     RuntimeEnabled=WebXR
 ] interface XRViewerPose : XRPose {
-  [SameObject] readonly attribute FrozenArray<XRView> views;
+  [SameObject, SaveSameObject] readonly attribute FrozenArray<XRView> views;
 };
diff --git a/third_party/blink/renderer/platform/bindings/v8_private_property.h b/third_party/blink/renderer/platform/bindings/v8_private_property.h
index f8545746..fdd9694d 100644
--- a/third_party/blink/renderer/platform/bindings/v8_private_property.h
+++ b/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -50,6 +50,10 @@
   X(SameObject, PerformanceLongTaskTimingAttribution)   \
   X(SameObject, PerformanceObserverSupportedEntryTypes) \
   X(SameObject, PushManagerSupportedContentEncodings)   \
+  X(SameObject, XRInputSourceProfiles)                  \
+  X(SameObject, XRInputSourcesChangeEventAdded)         \
+  X(SameObject, XRInputSourcesChangeEventRemoved)       \
+  X(SameObject, XRViewerPoseViews)                      \
   SCRIPT_PROMISE_PROPERTIES(X, Promise)                 \
   SCRIPT_PROMISE_PROPERTIES(X, Resolver)
 
diff --git a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
index 56e3949..0125317 100644
--- a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
@@ -79,8 +79,7 @@
     return nullptr;  // Can happen if the context is lost.
 
   sk_sp<SkImage> sk_image = paint_image_.GetSkImage();
-  sk_sp<SkImage> gpu_skimage =
-      sk_image->makeTextureImage(grcontext, sk_image->colorSpace());
+  sk_sp<SkImage> gpu_skimage = sk_image->makeTextureImage(grcontext);
   if (!gpu_skimage)
     return nullptr;
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a1962a2..d27a699a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1645,6 +1645,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-with-padding.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-with-single-empty-block.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-with-single-tall-line.html [ Failure ]
+crbug.com/994172 virtual/layout_ng_experimental/fast/multicol/nested-with-spanner-inside-margins-crash.html [ Crash ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-with-tall-block.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/newmulticol/avoid-column-break-inside.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/newmulticol/balance2.html [ Failure ]
@@ -1935,7 +1936,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-001.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-003.html [ Failure ]
 crbug.com/807497 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/auto-margins-001.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse.html [ Failure ]
@@ -1997,6 +1997,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-001.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-002.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html [ Pass Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/scrollbars-auto.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/scrollbars.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/table-as-item-auto-min-width.html [ Failure ]
@@ -3243,6 +3244,10 @@
 crbug.com/994214 external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-display/display-flow-root-list-item-001.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-display/display-flow-root-list-item-001.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-display/display-flow-root-list-item-001.html [ Failure ]
+crbug.com/626703 [ Mac10.10 ] external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.13 ] wpt_internal/display-lock/rendersubtree/activation/selection.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-lists/li-value-reversed-005.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-lists/li-value-reversed-005.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 6040525f5..be39bec 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -41569,6 +41569,18 @@
      {}
     ]
    ],
+   "css/css-display/display-flow-root-list-item-001.html": [
+    [
+     "css/css-display/display-flow-root-list-item-001.html",
+     [
+      [
+       "/css/css-display/display-flow-root-list-item-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display/display-inline-dynamic-001.html": [
     [
      "css/css-display/display-inline-dynamic-001.html",
@@ -58847,6 +58859,18 @@
      {}
     ]
    ],
+   "css/css-paint-api/color-custom-property-animation.https.html": [
+    [
+     "css/css-paint-api/color-custom-property-animation.https.html",
+     [
+      [
+       "/css/css-paint-api/color-custom-property-animation-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-paint-api/custom-property-animation-on-main-thread.https.html": [
     [
      "css/css-paint-api/custom-property-animation-on-main-thread.https.html",
@@ -133214,6 +133238,9 @@
    "css/css-display/display-flow-root-001-ref.html": [
     []
    ],
+   "css/css-display/display-flow-root-list-item-001-ref.html": [
+    []
+   ],
    "css/css-display/display-inline-dynamic-001-ref.html": [
     []
    ],
@@ -141095,6 +141122,9 @@
    "css/css-paint-api/background-repeat-x-ref.html": [
     []
    ],
+   "css/css-paint-api/color-custom-property-animation-ref.html": [
+    []
+   ],
    "css/css-paint-api/geometry-background-image-001-ref.html": [
     []
    ],
@@ -207184,6 +207214,30 @@
      {}
     ]
    ],
+   "css/css-position/animations/bottom-interpolation.html": [
+    [
+     "css/css-position/animations/bottom-interpolation.html",
+     {}
+    ]
+   ],
+   "css/css-position/animations/left-interpolation.html": [
+    [
+     "css/css-position/animations/left-interpolation.html",
+     {}
+    ]
+   ],
+   "css/css-position/animations/right-interpolation.html": [
+    [
+     "css/css-position/animations/right-interpolation.html",
+     {}
+    ]
+   ],
+   "css/css-position/animations/top-interpolation.html": [
+    [
+     "css/css-position/animations/top-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-position/inheritance.html": [
     [
      "css/css-position/inheritance.html",
@@ -209164,6 +209218,12 @@
      {}
     ]
    ],
+   "css/css-sizing/animation/width-interpolation.html": [
+    [
+     "css/css-sizing/animation/width-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-sizing/aspect-ratio-affects-container-width-when-height-changes.html": [
     [
      "css/css-sizing/aspect-ratio-affects-container-width-when-height-changes.html",
@@ -250812,6 +250872,12 @@
      {}
     ]
    ],
+   "infrastructure/assumptions/document-fonts-ready.html": [
+    [
+     "infrastructure/assumptions/document-fonts-ready.html",
+     {}
+    ]
+   ],
    "infrastructure/assumptions/html-elements.html": [
     [
      "infrastructure/assumptions/html-elements.html",
@@ -289015,6 +289081,12 @@
      {}
     ]
    ],
+   "svg/animations/scripted/paced-value-animation-overwrites-keyTimes.html": [
+    [
+     "svg/animations/scripted/paced-value-animation-overwrites-keyTimes.html",
+     {}
+    ]
+   ],
    "svg/animations/single-values-animation.html": [
     [
      "svg/animations/single-values-animation.html",
@@ -303438,6 +303510,12 @@
      }
     ]
    ],
+   "webxr/navigator_xr_sameObject.https.html": [
+    [
+     "webxr/navigator_xr_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/render_state_vertical_fov_immersive.https.html": [
     [
      "webxr/render_state_vertical_fov_immersive.https.html",
@@ -303558,6 +303636,12 @@
      {}
     ]
    ],
+   "webxr/xrFrame_session_sameObject.https.html": [
+    [
+     "webxr/xrFrame_session_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrInputSource_add_remove.https.html": [
     [
      "webxr/xrInputSource_add_remove.https.html",
@@ -303582,6 +303666,18 @@
      {}
     ]
    ],
+   "webxr/xrInputSource_sameObject.https.html": [
+    [
+     "webxr/xrInputSource_sameObject.https.html",
+     {}
+    ]
+   ],
+   "webxr/xrPose_transform_sameObject.https.html": [
+    [
+     "webxr/xrPose_transform_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrRay_constructor.https.html": [
     [
      "webxr/xrRay_constructor.https.html",
@@ -303624,6 +303720,12 @@
      {}
     ]
    ],
+   "webxr/xrRigidTransform_sameObject.https.html": [
+    [
+     "webxr/xrRigidTransform_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrSession_cancelAnimationFrame.https.html": [
     [
      "webxr/xrSession_cancelAnimationFrame.https.html",
@@ -303690,6 +303792,12 @@
      {}
     ]
    ],
+   "webxr/xrSession_sameObject.https.html": [
+    [
+     "webxr/xrSession_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrSession_viewer_referenceSpace.https.html": [
     [
      "webxr/xrSession_viewer_referenceSpace.https.html",
@@ -303726,6 +303834,18 @@
      {}
     ]
    ],
+   "webxr/xrView_sameObject.https.html": [
+    [
+     "webxr/xrView_sameObject.https.html",
+     {}
+    ]
+   ],
+   "webxr/xrViewerPose_views_sameObject.https.html": [
+    [
+     "webxr/xrViewerPose_views_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrViewport_valid.https.html": [
     [
      "webxr/xrViewport_valid.https.html",
@@ -303744,6 +303864,12 @@
      {}
     ]
    ],
+   "webxr/xrWebGLLayer_framebuffer_sameObject.https.html": [
+    [
+     "webxr/xrWebGLLayer_framebuffer_sameObject.https.html",
+     {}
+    ]
+   ],
    "webxr/xrWebGLLayer_framebuffer_scale.https.html": [
     [
      "webxr/xrWebGLLayer_framebuffer_scale.https.html",
@@ -353191,6 +353317,14 @@
    "3d1dcb020df129dd10d66bb4b04d62c3c280cfb6",
    "reftest"
   ],
+  "css/css-display/display-flow-root-list-item-001-ref.html": [
+   "00bfbca26a6036692746a8c2689831f1fcc21427",
+   "support"
+  ],
+  "css/css-display/display-flow-root-list-item-001.html": [
+   "6c5bece5864aa15f7bd34b26055ed755b43db1f1",
+   "reftest"
+  ],
   "css/css-display/display-inline-dynamic-001-ref.html": [
    "8b5f5015f9ebc818cbf48666773440a359e1d740",
    "support"
@@ -366348,7 +366482,7 @@
    "reftest"
   ],
   "css/css-grid/animation/grid-template-columns-interpolation-expected.txt": [
-   "9503924d5fff2afb61b333ff6f197c8880632eef",
+   "dad4474d40e35885731e96b2b0dad4d9c60a4844",
    "support"
   ],
   "css/css-grid/animation/grid-template-columns-interpolation.html": [
@@ -366364,7 +366498,7 @@
    "reftest"
   ],
   "css/css-grid/animation/grid-template-rows-interpolation-expected.txt": [
-   "8dd30bef598826e4cf50583ebdb0c66ff11232ad",
+   "2a2a6d8389188041751a5108b76a300dd66fee8c",
    "support"
   ],
   "css/css-grid/animation/grid-template-rows-interpolation.html": [
@@ -372899,6 +373033,14 @@
    "2eccfd2a7d0b6e894a66f1afedc6969090f8ad9c",
    "reftest"
   ],
+  "css/css-paint-api/color-custom-property-animation-ref.html": [
+   "3439cd9364560c870b09a394887daec5969b6bd4",
+   "support"
+  ],
+  "css/css-paint-api/color-custom-property-animation.https.html": [
+   "5cbfee89c45dd37e165676a835ece3f6283d0957",
+   "reftest"
+  ],
   "css/css-paint-api/custom-property-animation-on-main-thread.https.html": [
    "13ccf3fc27372d9494e09a36095140e4dbef236b",
    "reftest"
@@ -373423,6 +373565,22 @@
    "8f03d3c62fd0cefb11a22b1a4a8d2c06fed97308",
    "support"
   ],
+  "css/css-position/animations/bottom-interpolation.html": [
+   "272e79fc05b0267afe696c11ea0572299559d223",
+   "testharness"
+  ],
+  "css/css-position/animations/left-interpolation.html": [
+   "33ed0b4ec3b961bc0f71fc1b784b51201f50ebfa",
+   "testharness"
+  ],
+  "css/css-position/animations/right-interpolation.html": [
+   "284d435e56eac5370edd570d2f67b0dfeaa6bbf6",
+   "testharness"
+  ],
+  "css/css-position/animations/top-interpolation.html": [
+   "f5af530c387a7b52a78a4ca13b27d976f60b2dc9",
+   "testharness"
+  ],
   "css/css-position/fixed-z-index-blend-ref.html": [
    "2675401b4092996c2b3c3b80426f2730dc7bbf5f",
    "support"
@@ -377031,6 +377189,10 @@
    "086e654a8e039f259b5e828d024f808c2e95016b",
    "support"
   ],
+  "css/css-sizing/animation/width-interpolation.html": [
+   "33bc1b14c83f45afbea4cdfadbe3959ac829e615",
+   "testharness"
+  ],
   "css/css-sizing/aspect-ratio-affects-container-width-when-height-changes.html": [
    "0dbbb2f9404da7cfa89f2e75af3ca06cfbe4be7e",
    "testharness"
@@ -386356,7 +386518,7 @@
    "testharness"
   ],
   "css/css-transforms/animation/list-interpolation-expected.txt": [
-   "7ead4e5f22ab385eaf574fadaf540a90a5a9ee2d",
+   "29ac41d17d51dca5687b4dab7388fe40e4eabb97",
    "support"
   ],
   "css/css-transforms/animation/list-interpolation.html": [
@@ -391932,7 +392094,7 @@
    "testharness"
   ],
   "css/css-transitions/CSSTransition-effect.tentative.html": [
-   "41bd23eb53122ed228eb18c3c3e73148b7e2e20e",
+   "a38bc21bde05b95f14963d3a6543cef40f193e5a",
    "testharness"
   ],
   "css/css-transitions/CSSTransition-finished.tentative.html": [
@@ -409980,7 +410142,7 @@
    "support"
   ],
   "css/support/interpolation-testcommon.js": [
-   "c0a82fd079225ceb8fd89e46eba586071d171a09",
+   "930d8a09bb451bfff69a10942b2f9e1a00feb9f7",
    "support"
   ],
   "css/support/parsing-testcommon.js": [
@@ -427992,7 +428154,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/coep-navigate-popup.https.html": [
-   "717122b4b2f2e766a8fe172a8751f5e6c63d0e8a",
+   "21320a61b2eaa8b17cbb518d2028a5dce4134bf7",
    "testharness"
   ],
   "html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers": [
@@ -428052,7 +428214,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-none.https-expected.txt": [
-   "c87bb79b0487afb1b8351a442dc74f951f3ea9f8",
+   "441401ec1eb68b9cc27167f78234bb99231dfaab",
    "support"
   ],
   "html/cross-origin-opener-policy/popup-none.https.html": [
@@ -428068,7 +428230,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https-expected.txt": [
-   "00cee67cafed54c020f503ee01668f55b5beee6f",
+   "559011a753fb7333312e49f7d67b4dfa3a7c7137",
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https.html": [
@@ -428080,7 +428242,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-origin.https-expected.txt": [
-   "52706c957914a89537deb6169098552d788a4fbf",
+   "0d082385b18e4696af0a53b727bec932fb86af6b",
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-origin.https.html": [
@@ -428092,7 +428254,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt": [
-   "a0bab410d175c6d45109ee6d12c4b7f7bff1ddd1",
+   "2dfbfd706e72c10acd53822964ef477939ea1385",
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https.html": [
@@ -428104,7 +428266,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-site.https-expected.txt": [
-   "11982b6a8955893670028c20ef0c58316999b04c",
+   "dd1e4548e8bd75f0610ce3fa58abc128264755c0",
    "support"
   ],
   "html/cross-origin-opener-policy/popup-same-site.https.html": [
@@ -428116,7 +428278,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/resources/common.js": [
-   "b60093f1c62c5d77b213ed95e25ee468b2c2200c",
+   "c5d3c6c1084668ecd3ff02615725c7c3dc6117bb",
    "support"
   ],
   "html/cross-origin-opener-policy/resources/coop-coep.py": [
@@ -445775,6 +445937,10 @@
    "5d5b0dc0e108a823ef16614e9c2c91f5ea142543",
    "testharness"
   ],
+  "infrastructure/assumptions/document-fonts-ready.html": [
+   "9fb0137025b63b7fad191af3d2a0a941cd573870",
+   "testharness"
+  ],
   "infrastructure/assumptions/html-elements.html": [
    "3fe3d201ff649aca36e49b6b78cd48a94db26806",
    "testharness"
@@ -478375,6 +478541,10 @@
    "86a0a40fa2de116c5b2076641180b24688d56f9b",
    "testharness"
   ],
+  "svg/animations/scripted/paced-value-animation-overwrites-keyTimes.html": [
+   "56f67dc5ed1ceeeea347b703f5048b289f95131b",
+   "testharness"
+  ],
   "svg/animations/single-values-animation.html": [
    "40aa3461866cf4c32316d86216dcfe4298be7718",
    "testharness"
@@ -496348,15 +496518,15 @@
    "testharness"
   ],
   "webxr/events_input_sources_change.https.html": [
-   "bc2b2a95e40b0d700e8d18c9dc953b84ec9fbcde",
+   "107cc9b544e3a395c14655d0f4356485f05d7bf5",
    "testharness"
   ],
   "webxr/events_referenceSpace_reset.https.html": [
-   "f15ffc52a8845b7e2cdd6ddb4a9b7f06c1c3e5e0",
+   "5466d9e3369a250439fd56dc302896f7d4200cf9",
    "testharness"
   ],
   "webxr/events_session_select.https.html": [
-   "b74d5ea02dbefa51311d592fbf26019f06790ec2",
+   "396d6b23939f96a2f29151eac21548cd97f92009",
    "testharness"
   ],
   "webxr/events_session_select_subframe.https.html": [
@@ -496379,6 +496549,10 @@
    "3e54e367787cb95dada398790fe23b10174df29f",
    "testharness"
   ],
+  "webxr/navigator_xr_sameObject.https.html": [
+   "56cd65c4e42dbe7bb9d652547e65f0491e05f831",
+   "testharness"
+  ],
   "webxr/render_state_vertical_fov_immersive.https.html": [
    "485438cabf6a633df42a0f94c04922e7274013e1",
    "testharness"
@@ -496479,6 +496653,10 @@
    "c7af792c7bb45155c1a24e177ed3be05875872d6",
    "testharness"
   ],
+  "webxr/xrFrame_session_sameObject.https.html": [
+   "cbbef68713b2991945827899407036a8a9205a14",
+   "testharness"
+  ],
   "webxr/xrInputSource_add_remove.https.html": [
    "4c50670c70ec87754a777cc0bcfe8272e794ca07",
    "testharness"
@@ -496495,6 +496673,14 @@
    "32073c631f8ecfc3b19c33ed03e6b9999553cfec",
    "testharness"
   ],
+  "webxr/xrInputSource_sameObject.https.html": [
+   "78240de2f9019218061e45359cfad7cd28057d52",
+   "testharness"
+  ],
+  "webxr/xrPose_transform_sameObject.https.html": [
+   "79eed4cdec4663b3a0a401aff80126e4dad767f9",
+   "testharness"
+  ],
   "webxr/xrRay_constructor.https.html": [
    "b955db4509c2f60facee570e6011a1441297e3dd",
    "testharness"
@@ -496523,6 +496709,10 @@
    "df804193ffe9eb87dbb16383cb333a5fe0a06546",
    "testharness"
   ],
+  "webxr/xrRigidTransform_sameObject.https.html": [
+   "d014fe6fb56766a636559db67abc06428a88e98c",
+   "testharness"
+  ],
   "webxr/xrSession_cancelAnimationFrame.https.html": [
    "6a294f21f06d98483d9278d08e50124d84779aad",
    "testharness"
@@ -496532,7 +496722,7 @@
    "testharness"
   ],
   "webxr/xrSession_end.https.html": [
-   "b91a5b977cab3d2fbb5c4989246f45b0c9b2024b",
+   "e8c078ead9b7eaf4ed4312f14945ddfa07994614",
    "testharness"
   ],
   "webxr/xrSession_input_events_end.https.html": [
@@ -496567,6 +496757,10 @@
    "1bd516ee12e1d3ba24fd13ff04974c72e284b38a",
    "testharness"
   ],
+  "webxr/xrSession_sameObject.https.html": [
+   "837fa0a008d6cdfcbd9ee134e7ec78bce7c2b95b",
+   "testharness"
+  ],
   "webxr/xrSession_viewer_referenceSpace.https.html": [
    "fd6082bc3468f094953152d220fceafa083baf76",
    "testharness"
@@ -496591,6 +496785,14 @@
    "9404fcb8aaf33876f2918d3796190f16feafe506",
    "testharness"
   ],
+  "webxr/xrView_sameObject.https.html": [
+   "1213bcb1f1166a876ecb7e0d76260092525e3cd6",
+   "testharness"
+  ],
+  "webxr/xrViewerPose_views_sameObject.https.html": [
+   "ec1ee6964f0ddcfc93e1be13ff0b4d09a2af59ec",
+   "testharness"
+  ],
   "webxr/xrViewport_valid.https.html": [
    "1b7d982d596187f1381bee73eac2990900a37f8f",
    "testharness"
@@ -496603,6 +496805,10 @@
    "dd40865e445aafce88f5941f4127236c36f01f2d",
    "testharness"
   ],
+  "webxr/xrWebGLLayer_framebuffer_sameObject.https.html": [
+   "b0f637863b6aec46d36d3d1400219ce7aebb494a",
+   "testharness"
+  ],
   "webxr/xrWebGLLayer_framebuffer_scale.https.html": [
    "7b5cedb1c83987daf435f662e5687cf6e1bb0559",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001-ref.html
new file mode 100644
index 0000000..00bfbca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: display:flow-root list-item</title>
+  <link rel="author" title="Mats Palmgren" href="">
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+body { padding-left: 100px; }
+
+.float {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: pink;
+}
+
+.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}
+
+  </style>
+</head>
+<body>
+
+<div style="border:1px solid">
+  <div style="margin: 40px 0">
+    <div style="display:list-item">x</div>
+  </div>
+</div>
+
+<div style="border:1px solid">
+  <div style="display:list-item" class="float"></div>
+  <div class="clearfix"></div>
+</div>
+
+<div style="border:1px solid">
+  <div class="float"></div>
+  <div style="display:list-item; border:1px solid; margin-left:20px">x</div>
+</div>
+
+<span>
+  <span style="display:list-item; background:grey; margin:20px 0 0 21px"><div style="padding:20px">x</div></span>
+</span>
+
+<div style="display:list-item; border:3px solid; height:10px;"></div>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001.html
new file mode 100644
index 0000000..6c5bece5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-flow-root-list-item-001.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Display Test: display:flow-root list-item</title>
+  <link rel="author" title="Mats Palmgren" href="">
+  <link rel="help" href="https://drafts.csswg.org/css-display-3/#list-items">
+  <link rel="match" href="display-flow-root-list-item-001-ref.html">
+  <style type="text/css">
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+body { padding-left: 100px; }
+
+.float {
+  float: left;
+  width: 20px;
+  height: 40px;
+  background: pink;
+}
+
+.li { display: flow-root list-item; }
+  </style>
+</head>
+<body>
+
+<div style="border:1px solid">
+  <!-- this tests that the flow-root margins don't collapse with its children. -->
+  <span class="li" style="margin: 20px 0">
+    <div style="margin: 20px 0">x</div>
+  </span>
+</div>
+
+<div style="border:1px solid">
+  <!-- this tests that the flow-root grows to fit child floats -->
+  <span class="li"><div class="float"></div></span>
+</div>
+
+<div style="border:1px solid; margin-bottom:20px">
+  <!-- this tests that a float does not intrude into flow-root box -->
+  <div class="float"></div>
+  <span class="li" style="border:1px solid">x</span>
+</div>
+
+<span>
+  <!-- this tests that a flow-root box is constructed also in the "ibsplit" case -->
+  <span class="li" style="background:grey;"><div style="margin:20px">x</div></span>
+</span>
+
+<span class="li" style="border:3px solid; height:10px;">
+  <!-- this tests that a flow-root fills the available width, and that 'height' applies -->
+</span>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-absolute-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/absolute-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-absolute-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/absolute-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-absolute.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/absolute.https.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-absolute.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/absolute.https.html
index bf81b21..7a726f6e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-absolute.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/absolute.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#interaction-sizing">
-<link rel="match" href="auto-block-size-absolute-ref.html">
+<link rel="match" href="absolute-ref.html">
 <meta name="assert" content="This test checks that the absolute positioning respects the auto-block-size." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-flex-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/flex-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-flex-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/flex-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-flex.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/flex.https.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-flex.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/flex.https.html
index 5b152bb..96fe3c7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-flex.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/flex.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#interaction-sizing">
-<link rel="match" href="auto-block-size-flex-ref.html">
+<link rel="match" href="flex-ref.html">
 <meta name="assert" content="This test checks that the flex layout respects the auto-block-size." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-floats-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/floats-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-floats-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/floats-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-floats.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/floats.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-floats.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/floats.https.html
index 342c57b..b36f89d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-floats.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/floats.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#interaction-sizing">
-<link rel="match" href="auto-block-size-floats-ref.html">
+<link rel="match" href="floats-ref.html">
 <meta name="assert" content="This test checks that if the layout() is a float, the flow layout respects the auto-block-size." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-inflow-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/inflow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-inflow-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/inflow-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-inflow.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/inflow.https.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-inflow.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/inflow.https.html
index 7daef6e4..2239b278 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-inflow.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/inflow.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#interaction-sizing">
-<link rel="match" href="auto-block-size-inflow-ref.html">
+<link rel="match" href="inflow-ref.html">
 <meta name="assert" content="This test checks that min/max-block-size constraints are applied correctly to a layout()." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-negative-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/negative-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-negative-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/negative-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-negative.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/negative.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-negative.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/negative.https.html
index 392edd1..a1a76d9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size-negative.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/auto-block-size/negative.https.html
@@ -1,9 +1,8 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#interaction-sizing">
-<link rel="match" href="auto-block-size-negative-ref.html">
+<link rel="match" href="negative-ref.html">
 <meta name="assert" content="This test checks that auto-block-size is correctly clamped to zero." />
-<meta name="assert" content="TODO" />
 
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-htb-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-htb-vrl.https.html
index 0da20ee..6ec8e40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-htb-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-htb-vrl.https.html
@@ -61,5 +61,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-invalid.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-invalid.https.html
index dfbc8125..32a0f11 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-invalid.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-invalid.https.html
@@ -45,5 +45,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-vrl-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-vrl-htb.https.html
index c8e84ae..536af3b5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-vrl-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-block-size-vrl-htb.https.html
@@ -61,5 +61,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-htb-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-htb-htb.https.html
index 94cf75f..6205c01 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-htb-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-htb-htb.https.html
@@ -61,5 +61,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-invalid.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-invalid.https.html
index 136d13f..8bb18aaa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-invalid.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-invalid.https.html
@@ -45,5 +45,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-vrl-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-vrl-vrl.https.html
index 392a6b5..1b8d01f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-vrl-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-inline-size-vrl-vrl.https.html
@@ -61,5 +61,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-htb.https.html
index 960fb7d7..9bf4d40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-htb.https.html
@@ -55,5 +55,5 @@
   <!-- A replaced percentage min-width/min-height should resolve itself against the available size. -->
   <img class="child" style="width: 5px; min-width: 20%; height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-vrl.https.html
index 0e9b557..eb104a1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-htb-vrl.https.html
@@ -55,5 +55,5 @@
   <!-- A replaced percentage min-width/min-height should resolve itself against the available size. -->
   <img class="child" style="width: 5px; min-width: 20%; height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-invalid.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-invalid.https.html
index 62efe992..8bd9692 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-invalid.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-invalid.https.html
@@ -45,5 +45,5 @@
   <!-- For replaced elements, both axis should be resolved to 0px. -->
   <img class="child" style="--inline-size-expected: 0px; --block-size-expected: 0px; width: 100%; height: 100%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-htb.https.html
index 1352ea9..ce8ff95 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-htb.https.html
@@ -55,5 +55,5 @@
   <!-- A replaced percentage min-width/min-height should resolve itself against the available size. -->
   <img class="child" style="width: 5px; min-width: 20%; height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-vrl.https.html
index 9c30c21..71c7355 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/available-size-for-percentages-vrl-vrl.https.html
@@ -55,5 +55,5 @@
   <!-- A replaced percentage min-width/min-height should resolve itself against the available size. -->
   <img class="child" style="width: 5px; min-width: 20%; height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size-vrl.https.html
index dedcaa0e..631c5f8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size-vrl.https.html
@@ -56,5 +56,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size.https.html
index eea540c..737cc4d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-block-size.https.html
@@ -55,5 +55,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size-vrl.https.html
index 22bd3e7c..4fc3c2e7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size-vrl.https.html
@@ -56,5 +56,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size.https.html
index 0a05a46..0fdf4ac 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/fixed-inline-size.https.html
@@ -55,5 +55,5 @@
 </div>
 
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-htb.https.html
index 99224c7..84bda1dd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-htb.https.html
@@ -54,5 +54,5 @@
   <!-- A replaced percentage min-height should resolve itself against the percentageBlockSize. -->
   <img class="child" style="height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-vrl.https.html
index 8116d5a..98d285b0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-htb-vrl.https.html
@@ -54,5 +54,5 @@
   <!-- A replaced percentage min-width should resolve itself against the percentageInlineSize. -->
   <img class="child" style="width: 5px; min-width: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-invalid.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-invalid.https.html
index 932380a6..0435535 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-invalid.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-invalid.https.html
@@ -43,5 +43,5 @@
   <!-- A percentage shouldn't be resolved against an invalid percentageBlockSize. -->
   <img class="child" style="--inline-size-expected: 10px; --block-size-expected: 0px; height: 100%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-quirks-mode.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-quirks-mode.https.html
index 39a360d0..527149b6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-quirks-mode.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-quirks-mode.https.html
@@ -51,5 +51,5 @@
   </div>
 </div>
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-htb.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-htb.https.html
index 70640ef..2d3d496 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-htb.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-htb.https.html
@@ -54,5 +54,5 @@
   <!-- A replaced percentage min-height should resolve itself against the percentageInlineSize. -->
   <img class="child" style="height: 5px; min-height: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-vrl.https.html
index 0713257..577b98ad 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/percentage-size-vrl-vrl.https.html
@@ -54,5 +54,5 @@
   <!-- A replaced percentage min-width should resolve itself against the percentageBlockSize. -->
   <img class="child" style="width: 5px; min-width: 50%;" />
 <script>
-importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: '../support/layout-child-sizes-worklet.js'});
+importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, {url: 'support/layout-child-sizes-worklet.js'});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-child-sizes-worklet.js b/third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/support/layout-child-sizes-worklet.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-child-sizes-worklet.js
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/child-constraints/support/layout-child-sizes-worklet.js
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-left-right-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-left-right-vrl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-left-right-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-left-right-vrl.https.html
index 4a376d7..8e177db 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-left-right-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-left-right-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-none.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-none.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-none.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-none.https.html
index 7a695e0..7b10f11d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-none.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-none.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-top-bottom.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-top-bottom.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-top-bottom.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-top-bottom.https.html
index 7cbee82..73c29000 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-absolute-top-bottom.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-absolute-top-bottom.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none-vrl.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none-vrl.https.html
index 6f36abe73..704b66d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none.https.html
index 4fd6441c..6c023f5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-block-none.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-block-none.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-max.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-max.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-max.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-max.https.html
index accdd7c..8af6afd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-max.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-max.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-min.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-min.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-min.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-min.https.html
index 845683dc..4d76ed9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-min.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-min.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-vrl.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-vrl.https.html
index a319129a..bbc0a2f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed.https.html
index 646a514..45376ac 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-fixed.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-fixed.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-basis-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-basis-vrl.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-basis-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-basis-vrl.https.html
index bb12d15..25fc685 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-basis-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-basis-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-basis.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-basis.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-basis.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-basis.https.html
index 8435b02..8df99ee8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-basis.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-basis.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-grow.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-grow.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-grow.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-grow.https.html
index 68a3c19..da53fa86 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-grow.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-grow.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-none.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-none.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-none.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-none.https.html
index a0c416f5..1d4249e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-none.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-none.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-stretch-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-stretch-vrl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-stretch-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-stretch-vrl.https.html
index be448da..c71e202b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-column-stretch-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-column-stretch-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-grow-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-grow-vrl.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-grow-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-grow-vrl.https.html
index d79445e..f77b849 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-grow-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-grow-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-none.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-none.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-none.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-none.https.html
index f34a0d8..9ef11da 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-none.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-none.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-percentage-indefinite.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-percentage-indefinite.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-percentage-indefinite.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-percentage-indefinite.https.html
index ee8e27b..11112067 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-percentage-indefinite.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-percentage-indefinite.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch-max.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch-max.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch-max.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch-max.https.html
index bbf358e..c72ed3e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch-max.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch-max.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch.https.html
index 1b1e438..cfaf382 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-flex-stretch.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-flex-stretch.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-none.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-none.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-none.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-none.https.html
index 27b68a0..5c738152 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-none.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-none.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch-max.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch-max.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch-max.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch-max.https.html
index 108c90d..c738ad5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch-max.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch-max.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch.https.html
index f93ad5b..2e83f42c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-stretch.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-stretch.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-vrl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-vrl.https.html
index db82767..2c004cd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-grid-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-grid-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-indefinite.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-indefinite.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-indefinite.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-indefinite.https.html
index 94a2038..ab02cb4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-indefinite.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-indefinite.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-quirks-mode.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-quirks-mode.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-quirks-mode.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-quirks-mode.https.html
index 9bd9044..285ce941 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-quirks-mode.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-quirks-mode.https.html
@@ -1,6 +1,6 @@
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-vrl.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-vrl.https.html
index 8c7a8c5d..870bc526 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage.https.html
index 693553e..33555655 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-percentage.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-percentage.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-quirky-body.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-quirky-body.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-quirky-body.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-quirky-body.https.html
index 7601e8b..150426d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-block-size-quirky-body.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-block-size-quirky-body.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedblocksize">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedBlockSize is passed into the layout function correctly." />
 <style>
 iframe { border: none; width: 200px; height: 200px; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-left-right.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-left-right.https.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-left-right.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-left-right.https.html
index 6b3662a..3b81c4d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-left-right.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-left-right.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-top-bottom-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-top-bottom-vrl.https.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-top-bottom-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-top-bottom-vrl.https.html
index 632a5dd..ec94e59a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-top-bottom-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-absolute-top-bottom-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats-vlr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats-vlr.https.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats-vlr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats-vlr.https.html
index a8f4dd3..2758462 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats-vlr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats-vlr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats.https.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats.https.html
index 2eb6197..862b9ad 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-avoid-floats.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-avoid-floats.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-vlr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-vlr.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-vlr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-vlr.https.html
index 751ea5e..0c15fd1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto-vlr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto-vlr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto.https.html
index 1458a8b..c513c3d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-block-auto.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-block-auto.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed-vrl.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed-vrl.https.html
index 39ea818..93b0c11 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed.https.html
index 6434d33..d8e8062 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-fixed.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-fixed.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow-column-vrl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow-column-vrl.https.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow-column-vrl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow-column-vrl.https.html
index 263d45e5..b915996 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow-column-vrl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow-column-vrl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow.https.html
index d2589e62..c2532c1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-flex-grow.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-flex-grow.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-grid.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-grid.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-grid.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-grid.https.html
index 94eca6b..45f9f49 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-grid.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-grid.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage-vlr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage-vlr.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage-vlr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage-vlr.https.html
index 0efabcb..2e350437 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage-vlr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage-vlr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage.https.html
index 4b5a567..c9041cf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-percentage.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-percentage.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#dom-layoutconstraints-fixedinlinesize">
-<link rel="match" href="constraints-fixed-inline-size-ref.html">
+<link rel="match" href="fixed-inline-size-ref.html">
 <meta name="assert" content="This test checks that LayoutConstraints#fixedInlineSize is passed into the layout function correctly." />
 <style>
 body {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints-fixed-inline-size-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/fixed-inline-size-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-block-size-quirky-body-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-block-size-quirky-body-iframe.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-block-size-quirky-body-iframe.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-block-size-quirky-body-iframe.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-block-size.js b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-block-size.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-block-size.js
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-block-size.js
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-inline-size.js b/third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-inline-size.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/constraints-fixed-inline-size.js
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/constraints/support/constraints-fixed-inline-size.js
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/crash-multicol.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/crash-multicol.https.html
index dbcbd18..5f17510 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/crash-multicol.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/crash-multicol.https.html
@@ -14,8 +14,15 @@
 
 <div id="test"></div>
 
+<script id="code" type="text/worklet">
+registerLayout('test', class {
+  async intrinsicSizes() {}
+  async layout() {}
+});
+</script>
+
 <script>
 promise_test(async function() {
-  await importWorklet(CSS.layoutWorklet, {url: 'support/layout-position-child-worklet.js'});
+  await importWorklet(CSS.layoutWorklet, document.getElementById('code').textContent);
 });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-return.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/bad-return.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-return.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/bad-return.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-constructor-error.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/constructor-error.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-constructor-error.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/constructor-error.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-error.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/error.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-error.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/error.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/fallback-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/fallback-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-invalid-child.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/invalid-child.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-invalid-child.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/invalid-child.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-invalid-fragment.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/invalid-fragment.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-invalid-fragment.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/invalid-fragment.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-no-promise.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/no-promise.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-no-promise.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/no-promise.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-unresolved-promise.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/unresolved-promise.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout-unresolved-promise.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/fallback-layout/unresolved-promise.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-absolute.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/absolute.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-absolute.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/absolute.https.html
index 26513f4..7c47e38e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-absolute.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/absolute.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that absolute children don't appear in the children array." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-before-after.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/before-after.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-before-after.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/before-after.https.html
index 4923f26c..373392d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-before-after.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/before-after.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that boxes created by ::before/::after appear as children." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-fixed.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/fixed.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-fixed.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/fixed.https.html
index 264fc638..95d8852 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-fixed.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/fixed.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that fixed children don't appear in the children array." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-float.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/float.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-float.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/float.https.html
index 6e40893e..e8db261 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-float.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/float.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that float children appear in the children array." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inflow.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inflow.https.html
similarity index 93%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inflow.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inflow.https.html
index 11f2b88a..b43f1a7f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inflow.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inflow.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that regular inflow children appear as children." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inlines-dynamic.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inlines-dynamic.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inlines-dynamic.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inlines-dynamic.https.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inlines.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inlines.https.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inlines.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inlines.https.html
index 811af3f..dac7e0b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-inlines.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/inlines.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that inline children are correctly blockified or wrapped in anonymous boxes." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-child-worklet.js b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/support/layout-child-worklet.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-child-worklet.js
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/support/layout-child-worklet.js
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-text.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/text.https.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-text.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/text.https.html
index 40513f0..090034f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child-text.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/layout-child/text.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layout-children">
-<link rel="match" href="green-square-ref.html">
+<link rel="match" href="../green-square-ref.html">
 <meta name="assert" content="This test checks that text children are correctly blockified." />
 
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-ltr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-ltr.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-ltr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-ltr.https.html
index b09cb7067..f60109ca 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-ltr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-ltr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-rtl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-rtl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-rtl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-rtl.https.html
index 2d65b8cb..980a3cdc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-htb-rtl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/htb-rtl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-ref.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-ref.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-position-child-worklet.js b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/support/layout-position-child-worklet.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/support/layout-position-child-worklet.js
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/support/layout-position-child-worklet.js
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-ltr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-ltr.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-ltr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-ltr.https.html
index 62a5980..d75a4af 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-ltr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-ltr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-rtl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-rtl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-rtl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-rtl.https.html
index a9983b1..a8ef6c6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vlr-rtl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vlr-rtl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-ltr.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-ltr.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-ltr.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-ltr.https.html
index 0901285..21c9ce5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-ltr.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-ltr.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-rtl.https.html b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-rtl.https.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-rtl.https.html
rename to third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-rtl.https.html
index e16f26b1..777e725d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment-vrl-rtl.https.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/position-fragment/vrl-rtl.https.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
 <link rel="help" href="https://drafts.css-houdini.org/css-layout-api/#layoutfragment">
-<link rel="match" href="position-fragment-ref.html">
+<link rel="match" href="ref.html">
 <meta name="assert" content="This test checks that child fragments get positioned correctly." />
 <style>
 .test {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
index 41bd23eb..a38bc21b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/CSSTransition-effect.tentative.html
@@ -111,9 +111,10 @@
 
   // The transition needs to have a non-zero currentTime for the interruption
   // reversal logic to apply.
-  await singleFrame();
+  while (getComputedStyle(div).left == '0px') {
+    await singleFrame();
+  }
   assert_not_equals(transition.currentTime, 0);
-  assert_not_equals(getComputedStyle(div).left, '0px');
 
   // Without yielding to the rendering loop, set the current transition's
   // effect to null and interrupt the transition. This should work correctly.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-computed.html b/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-computed.html
new file mode 100644
index 0000000..84e598a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-computed.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#comp-func">
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#angles">
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#calc-type-checking">
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/computed-testcommon.js"></script>
+<div id="target"></div>
+<div id="reference"></div>
+<script>
+function test_angle_equals(value, expected) {
+  const reference = document.getElementById('reference');
+  reference.style.transform = '';
+  reference.style.transform = `rotate(${expected})`;
+  const computed = getComputedStyle(reference).transform;
+  test_computed_value('transform', `rotate(${value})`, computed);
+}
+
+// Identity tests
+test_angle_equals('min(1deg)', '1deg');
+test_angle_equals('min(1grad)', '1grad');
+test_angle_equals('min(1rad)', '1rad');
+test_angle_equals('min(1turn)', '1turn');
+test_angle_equals('max(1deg)', '1deg');
+test_angle_equals('max(1grad)', '1grad');
+test_angle_equals('max(1rad)', '1rad');
+test_angle_equals('max(1turn)', '1turn');
+
+// Comparisons between same units
+test_angle_equals('min(1deg, 2deg)', '1deg');
+test_angle_equals('min(1grad, 2grad)', '1grad');
+test_angle_equals('min(1rad, 2rad)', '1rad');
+test_angle_equals('min(1turn, 2turn)', '1turn');
+test_angle_equals('max(1deg, 2deg)', '2deg');
+test_angle_equals('max(1grad, 2grad)', '2grad');
+test_angle_equals('max(1rad, 2rad)', '2rad');
+test_angle_equals('max(1turn, 2turn)', '2turn');
+
+// Comparisons between different units
+test_angle_equals('min(90deg, 0.26turn)', '90deg');
+test_angle_equals('min(1.57rad, 95deg)', '1.57rad');
+test_angle_equals('max(91deg, 0.25turn)', '91deg');
+test_angle_equals('max(1.58rad, 90deg)', '1.58rad');
+
+// Nestings
+test_angle_equals('min(270deg, max(0.25turn, 3.14rad))', '3.14rad');
+test_angle_equals('max(0.25turn, min(270deg, 3.14rad))', '3.14rad');
+
+// General calculations
+test_angle_equals('calc(min(90deg, 1.58rad) + 0.25turn)', '180deg');
+test_angle_equals('calc(min(90deg, 1.58rad) - 0.125turn)', '45deg');
+test_angle_equals('calc(min(90deg, 1.58rad) * 2', '180deg');
+test_angle_equals('calc(min(90deg, 1.58rad) / 2', '45deg');
+test_angle_equals('calc(max(90deg, 1.56rad) + 0.25turn)', '180deg');
+test_angle_equals('calc(max(90deg, 1.56rad) - 0.125turn)', '45deg');
+test_angle_equals('calc(max(90deg, 1.56rad) * 2', '180deg');
+test_angle_equals('calc(max(90deg, 1.56rad) / 2', '45deg');
+test_angle_equals('calc(min(90deg, 1.58rad) + max(0.25turn, 99grad))', '180deg');
+test_angle_equals('calc(min(90deg, 1.58rad) - max(0.25turn, 99grad))', '0deg');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-invalid.html
new file mode 100644
index 0000000..29dc15d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/minmax-angle-invalid.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#comp-func">
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#angles">
+<link rel="help" href="https://drafts.csswg.org/css-values-4/#calc-type-checking">
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/parsing-testcommon.js"></script>
+<script>
+function test_invalid_angle(value) {
+  test_invalid_value('transform', `rotate(${value})`);
+}
+
+// Syntax checking
+test_invalid_angle('min()');
+test_invalid_angle('min( )');
+test_invalid_angle('min(,)');
+test_invalid_angle('min(1dag)');
+test_invalid_angle('min(1deg, )');
+test_invalid_angle('min(, 1deg)');
+test_invalid_angle('min(1deg + )');
+test_invalid_angle('min(1deg - )');
+test_invalid_angle('min(1deg * )');
+test_invalid_angle('min(1deg / )');
+test_invalid_angle('min(1deg 2deg)');
+test_invalid_angle('min(1deg, , 2deg)');
+test_invalid_angle('max()');
+test_invalid_angle('max( )');
+test_invalid_angle('max(,)');
+test_invalid_angle('max(1dag)');
+test_invalid_angle('max(1deg, )');
+test_invalid_angle('max(, 1deg)');
+test_invalid_angle('max(1deg + )');
+test_invalid_angle('max(1deg - )');
+test_invalid_angle('max(1deg * )');
+test_invalid_angle('max(1deg / )');
+test_invalid_angle('max(1deg 2deg)');
+test_invalid_angle('max(1deg, , 2deg)');
+
+// Type checking
+test_invalid_angle('min(0)');
+test_invalid_angle('min(0%)');
+test_invalid_angle('min(0px)');
+test_invalid_angle('min(0s)');
+test_invalid_angle('min(0Hz)');
+test_invalid_angle('min(0dpi)');
+test_invalid_angle('min(0fr)');
+test_invalid_angle('min(1deg, 0)');
+test_invalid_angle('min(1deg, 0%)');
+test_invalid_angle('min(1deg, 0px)');
+test_invalid_angle('min(1deg, 0s)');
+test_invalid_angle('min(1deg, 0Hz)');
+test_invalid_angle('min(1deg, 0dpi)');
+test_invalid_angle('min(1deg, 0fr)');
+test_invalid_angle('max(0)');
+test_invalid_angle('max(0%)');
+test_invalid_angle('max(0px)');
+test_invalid_angle('max(0s)');
+test_invalid_angle('max(0Hz)');
+test_invalid_angle('max(0dpi)');
+test_invalid_angle('max(0fr)');
+test_invalid_angle('max(1deg, 0)');
+test_invalid_angle('max(1deg, 0%)');
+test_invalid_angle('max(1deg, 0px)');
+test_invalid_angle('max(1deg, 0s)');
+test_invalid_angle('max(1deg, 0Hz)');
+test_invalid_angle('max(1deg, 0dpi)');
+test_invalid_angle('max(1deg, 0fr)');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js b/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
index 930d8a09..62f4079 100644
--- a/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/css/support/interpolation-testcommon.js
@@ -1,7 +1,6 @@
 'use strict';
 (function() {
   var interpolationTests = [];
-  var compositionTests = [];
   var cssAnimationsData = {
     sharedStyle: null,
     nextID: 0,
@@ -261,6 +260,16 @@
       target.measure = function() {
         var expectedValue = getComputedStyle(expectedTargetContainer.target).getPropertyValue(property);
         test(function() {
+          if (from && from !== neutralKeyframe) {
+            assert_true(CSS.supports(property, from), '\'from\' value should be supported');
+          }
+          if (to && to !== neutralKeyframe) {
+            assert_true(CSS.supports(property, to), '\'to\' value should be supported');
+          }
+          if (typeof underlying !== 'undefined') {
+            assert_true(CSS.supports(property, underlying), '\'underlying\' value should be supported');
+          }
+
           assert_equals(
             normalizeValue(getComputedStyle(target).getPropertyValue(property)),
             normalizeValue(expectedValue));
@@ -270,80 +279,14 @@
     });
   }
 
-  function createCompositionTestTargets(compositionContainer, compositionTest) {
-    var options = compositionTest.options;
-    var property = options.property;
-    var underlying = options.underlying;
-    var from = options.addFrom || options.replaceFrom;
-    var to = options.addTo || options.replaceTo;
-    var fromComposite = 'addFrom' in options ? 'add' : 'replace';
-    var toComposite = 'addTo' in options ? 'add' : 'replace';
-    if ('addFrom' in options === 'replaceFrom' in options
-      || 'addTo' in options === 'replaceTo' in options) {
-      test(function() {
-        assert_true('addFrom' in options !== 'replaceFrom' in options, 'addFrom xor replaceFrom must be specified');
-        assert_true('addTo' in options !== 'replaceTo' in options, 'addTo xor replaceTo must be specified');
-      }, `Composition tests must use addFrom xor replaceFrom, and addTo xor replaceTo`);
-    }
-    validateTestInputs(property, from, to, underlying);
-
-    var testText = `Compositing: property <${property}> underlying [${underlying}] from ${fromComposite} [${from}] to ${toComposite} [${to}]`;
-    var testContainer = createElement(compositionContainer, 'div');
-    createElement(testContainer, 'br');
-    return compositionTest.expectations.map(function(expectation) {
-      var actualTargetContainer = createTargetContainer(testContainer, 'actual');
-      var expectedTargetContainer = createTargetContainer(testContainer, 'expected');
-      expectedTargetContainer.target.style.setProperty(property, expectation.expect);
-      var target = actualTargetContainer.target;
-      target.style.setProperty(property, underlying);
-      target.interpolate = function() {
-        webAnimationsInterpolation.interpolateComposite(property, from, fromComposite, to, toComposite, expectation.at, target);
-      };
-      target.measure = function() {
-        var actualValue = getComputedStyle(target).getPropertyValue(property);
-        test(function() {
-          assert_equals(
-            normalizeValue(actualValue),
-            normalizeValue(getComputedStyle(expectedTargetContainer.target).getPropertyValue(property)));
-        }, `${testText} at (${expectation.at}) is [${sanitizeUrls(actualValue)}]`);
-      };
-      return target;
-    });
-  }
-
-  function validateTestInputs(property, from, to, underlying) {
-    if (from && from !== neutralKeyframe && !CSS.supports(property, from)) {
-        test(function() {
-          assert_unreached('from value not supported');
-        }, `${property} supports [${from}]`);
-    }
-    if (to && to !== neutralKeyframe && !CSS.supports(property, to)) {
-        test(function() {
-          assert_unreached('to value not supported');
-        }, `${property} supports [${to}]`);
-    }
-    if (typeof underlying !== 'undefined' && !CSS.supports(property, underlying)) {
-        test(function() {
-          assert_unreached('underlying value not supported');
-        }, `${property} supports [${underlying}]`);
-    }
-  }
-
-  function createTestTargets(interpolationMethods, interpolationTests, compositionTests, container) {
+  function createTestTargets(interpolationMethods, interpolationTests, container) {
     var targets = [];
-    for (var interpolationTest of interpolationTests) {
-      validateTestInputs(interpolationTest.options.property, interpolationTest.options.from, interpolationTest.options.to);
-    }
     for (var interpolationMethod of interpolationMethods) {
       var interpolationMethodContainer = createElement(container);
       for (var interpolationTest of interpolationTests) {
         [].push.apply(targets, createInterpolationTestTargets(interpolationMethod, interpolationMethodContainer, interpolationTest));
       }
     }
-    var compositionContainer = createElement(container);
-    for (var compositionTest of compositionTests) {
-      [].push.apply(targets, createCompositionTestTargets(compositionContainer, compositionTest));
-    }
     return targets;
   }
 
@@ -360,7 +303,7 @@
       webAnimationsInterpolation,
     ];
     var container = createElement(document.body);
-    var targets = createTestTargets(interpolationMethods, interpolationTests, compositionTests, container);
+    var targets = createTestTargets(interpolationMethods, interpolationTests, container);
     // Separate interpolation and measurement into different phases to avoid O(n^2) of the number of targets.
     for (var target of targets) {
       target.interpolate();
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html
new file mode 100644
index 0000000..baa866d0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src='/resources/testharness.js'></script>
+        <script src='/resources/testharnessreport.js'></script>
+    </head>
+    <body>
+        <img src="./oversized.jpg" alt="oversized image" width="50" height="50">
+    <script>
+        async_test(t => {
+            new ReportingObserver(
+                t.step_func_done((reports, _) => {
+                    assert_greater_than(reports.length, 0);
+                    const report = reports[0];
+                    assert_equals(report.type, "feature-policy-violation");
+                    assert_equals(report.url, document.location.href);
+                    const rbody = report.body;
+                    assert_equals(rbody.featureId, "oversized-images");
+                    assert_equals(rbody.sourceFile, document.getElementsByTagName('img')[0].src);
+                    assert_equals(rbody.lineNumber, null);
+                    assert_equals(rbody.columnNumber, null);
+                }),
+                {types: ['feature-policy-violation'], buffered: true}
+            ).observe();
+        },
+        "oversized-images Report Format")
+    </script>
+    </body>
+</html>
+
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html.headers b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html.headers
new file mode 100644
index 0000000..02bcbb9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized-images-reporting.html.headers
@@ -0,0 +1 @@
+Feature-Policy: oversized-images 'none'
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized.jpg b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized.jpg
new file mode 100644
index 0000000..497ed770
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/oversized.jpg
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-lossy-images-reporting.html b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-lossy-images-reporting.html
index 62a5469f..8dcf110d 100644
--- a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-lossy-images-reporting.html
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-lossy-images-reporting.html
@@ -13,6 +13,9 @@
   assert_equals(report.url, document.location.href);
   assert_equals(report.body.featureId, "unoptimized-lossy-images");
   assert_equals(report.body.disposition, "enforce");
+  assert_equals(report.body.sourceFile, document.getElementsByTagName('img')[0].src);
+  assert_equals(report.body.lineNumber, null);
+  assert_equals(report.body.columnNumber, null);
 };
 
 async_test(t => {
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
index 717122b4..21320a61 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy: a navigating popup</title>
+<meta content=timeout value=long>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src="/common/get-host-info.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-none.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-none.https-expected.txt
index c87bb79..441401ec 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-none.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-none.https-expected.txt
@@ -1,21 +1,21 @@
 This is a testharness.js-based test.
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
+PASS none document opening popup to https://web-platform.test:8444 with COOP: ""
+PASS none document opening popup to https://web-platform.test:8444 with COOP: "jibberish"
+FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "none_to_SAME_ORIGIN_same-site"
+FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_SAME_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "none_to_SAME_ORIGIN_same-origin"
+FAIL none document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_SAME_ORIGIN_same-origin-unsafe-allow-outgoing"
+PASS none document opening popup to https://www1.web-platform.test:8444 with COOP: ""
+PASS none document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish"
+FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "none_to_SAME_SITE_same-site"
+FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_SAME_SITE_same-site-unsafe-allow-outgoing"
+FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "none_to_SAME_SITE_same-origin"
+FAIL none document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_SAME_SITE_same-origin-unsafe-allow-outgoing"
+PASS none document opening popup to https://not-web-platform.test:8444 with COOP: ""
+PASS none document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish"
+FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "none_to_CROSS_ORIGIN_same-site"
+FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_CROSS_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "none_to_CROSS_ORIGIN_same-origin"
+FAIL none document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "none_to_CROSS_ORIGIN_same-origin-unsafe-allow-outgoing"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https-expected.txt
index 00cee67..559011a 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin-unsafe-allow-outgoing.https-expected.txt
@@ -1,21 +1,21 @@
 This is a testharness.js-based test.
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: ""
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "jibberish"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_ORIGIN_same-site"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_ORIGIN_same-origin"
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing"
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: ""
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_SITE_same-site"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_SITE_same-site-unsafe-allow-outgoing"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_SITE_same-origin"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_SAME_SITE_same-origin-unsafe-allow-outgoing"
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: ""
+PASS same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-site"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-origin"
+FAIL same-origin_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-origin-unsafe-allow-outgoing"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin.https-expected.txt
index 52706c9..0d082385 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-origin.https-expected.txt
@@ -1,21 +1,21 @@
 This is a testharness.js-based test.
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
+FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-origin_to_SAME_ORIGIN_"
+FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-origin_to_SAME_ORIGIN_jibberish"
+FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_to_SAME_ORIGIN_same-site"
+FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_SAME_ORIGIN_same-site-unsafe-allow-outgoing"
+PASS same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-origin"
+FAIL same-origin document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_SAME_ORIGIN_same-origin-unsafe-allow-outgoing"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-origin_to_SAME_SITE_"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-origin_to_SAME_SITE_jibberish"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_to_SAME_SITE_same-site"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_SAME_SITE_same-site-unsafe-allow-outgoing"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-origin_to_SAME_SITE_same-origin"
+FAIL same-origin document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_SAME_SITE_same-origin-unsafe-allow-outgoing"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_jibberish"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_same-site"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_same-origin"
+FAIL same-origin document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-origin_to_CROSS_ORIGIN_same-origin-unsafe-allow-outgoing"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt
index a0bab41..2dfbfd7 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt
@@ -1,21 +1,21 @@
 This is a testharness.js-based test.
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
+PASS same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: ""
+PASS same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "jibberish"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_ORIGIN_same-site"
+PASS same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_ORIGIN_same-origin"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_ORIGIN_same-origin-unsafe-allow-outgoing"
+PASS same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: ""
+PASS same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_SITE_same-site"
+PASS same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_SITE_same-origin"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_SAME_SITE_same-origin-unsafe-allow-outgoing"
+PASS same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: ""
+PASS same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-site"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-origin"
+FAIL same-site_unsafe-allow-outgoing document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_unsafe-allow-outgoing_to_CROSS_ORIGIN_same-origin-unsafe-allow-outgoing"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site.https-expected.txt
index 11982b6a..dd1e4548 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-same-site.https-expected.txt
@@ -1,21 +1,21 @@
 This is a testharness.js-based test.
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" mainTest is not defined
-FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" mainTest is not defined
+FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-site_to_SAME_ORIGIN_"
+FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-site_to_SAME_ORIGIN_jibberish"
+PASS same-site document opening popup to https://web-platform.test:8444 with COOP: "same-site"
+FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_SAME_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_to_SAME_ORIGIN_same-origin"
+FAIL same-site document opening popup to https://web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_SAME_ORIGIN_same-origin-unsafe-allow-outgoing"
+FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-site_to_SAME_SITE_"
+FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-site_to_SAME_SITE_jibberish"
+PASS same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site"
+FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_SAME_SITE_same-site-unsafe-allow-outgoing"
+FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_to_SAME_SITE_same-origin"
+FAIL same-site document opening popup to https://www1.web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_SAME_SITE_same-origin-unsafe-allow-outgoing"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "jibberish" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_jibberish"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-site" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_same-site"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-site unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_same-site-unsafe-allow-outgoing"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_same-origin"
+FAIL same-site document opening popup to https://not-web-platform.test:8444 with COOP: "same-origin unsafe-allow-outgoing" assert_equals: expected "" but got "same-site_to_CROSS_ORIGIN_same-origin-unsafe-allow-outgoing"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
index b60093f..c5d3c6c 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
@@ -29,7 +29,7 @@
   for (const test of tests) {
     async_test(t => {
       coop_test(t, test[0], test[1],
-                `${mainTest}_to_${test[0].name}_${test[1].replace(/ /g,"-")}`,
+                `${documentCOOPValueTitle}_to_${test[0].name}_${test[1].replace(/ /g,"-")}`,
                 test[2]);
     }, `${documentCOOPValueTitle} document opening popup to ${test[0].origin} with COOP: "${test[1]}"`);
   }
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/assumptions/document-fonts-ready.html b/third_party/blink/web_tests/external/wpt/infrastructure/assumptions/document-fonts-ready.html
new file mode 100644
index 0000000..9fb0137
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/assumptions/document-fonts-ready.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<title>document.fonts.ready resolves after layout depending on loaded fonts</title>
+<link rel="help" href="https://drafts.csswg.org/css-font-loading/#fontfaceset-pending-on-the-environment">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+  #foo {
+      font: 100px/1 Ahem;
+  }
+</style>
+<div id="log"></div>
+<span id="foo">X</span>
+<script>
+  // The purpose of this test is to ensure that testharness.js tests can use
+  // `document.fonts.ready` to wait for a web font to load, without having to
+  // wait for the window load event before or requestAnimationFrame after.
+  //
+  // The spec says that a FontFaceSet is "pending on the environment" if "the
+  // document has pending layout operations which might cause the user agent to
+  // request a font, or which depend on recently-loaded fonts", and both are
+  // assumed to hold true in this test.
+  async_test(t => {
+    assert_equals(document.fonts.size, 1, 'one font is pending');
+    document.fonts.ready.then(t.step_func_done(() => {
+      const span = document.getElementById('foo');
+      const rect = span.getBoundingClientRect();
+      // If Ahem has loaded, the X will be 100px wide.
+      assert_equals(rect.width, 100, 'span is 100px wide');
+    }));
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/events_input_sources_change.https.html b/third_party/blink/web_tests/external/wpt/webxr/events_input_sources_change.https.html
index bc2b2a9..107cc9b 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/events_input_sources_change.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/events_input_sources_change.https.html
@@ -24,6 +24,7 @@
     t.step(() => {
       inputChangeEvents++;
       assert_equals(event.session, session);
+      validateSameObject(event);
 
       // The first change event should be adding our controller.
       if (inputChangeEvents === 1) {
@@ -69,6 +70,23 @@
     });
   }
 
+  // Verifies that the same object is returned each time attributes are accessed
+  // on an XRInputSourcesChangeEvent, as required by the spec.
+  function validateSameObject(event) {
+    let eventSession = event.session;
+    let added = event.added;
+    let removed = event.removed;
+
+    t.step(() => {
+      assert_equals(eventSession, event.session,
+        "XRInputSourcesChangeEvent.session returns the same object.");
+      assert_equals(added, event.added,
+        "XRInputSourcesChangeEvent.added returns the same object.");
+      assert_equals(removed, event.removed,
+        "XRInputSourcesChangeEvent.removed returns the same object.");
+    });
+  }
+
   session.addEventListener('inputsourceschange', onInputSourcesChange, false);
 
   // Create our input source and immediately toggle the primary input so that
diff --git a/third_party/blink/web_tests/external/wpt/webxr/events_referenceSpace_reset.https.html b/third_party/blink/web_tests/external/wpt/webxr/events_referenceSpace_reset.https.html
index f15ffc5..5466d9e 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/events_referenceSpace_reset.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/events_referenceSpace_reset.https.html
@@ -21,7 +21,19 @@
     let eventWatcher = new EventWatcher(
         t, refSpace, ["reset", "watcherdone"]);
     refSpace.addEventListener("reset", (event) => {
-      assert_equals(event.referenceSpace, refSpace);
+      t.step(() => {
+        assert_equals(event.referenceSpace, refSpace);
+
+        // Also make sure the same objects are returned each time these
+        // attributes are accessed.
+        let eventRefSpace = event.referenceSpace;
+        let transform = event.transform;
+        assert_equals(eventRefSpace, event.referenceSpace,
+          "XRReferenceSpaceEvent.referenceSpace returns the same object.");
+        assert_equals(transform, event.transform,
+          "XRReferenceSpaceEvent.transform returns the same object.");
+      });
+
       refSpace.dispatchEvent(watcherDone);
     }, false);
     return eventWatcher.wait_for(["reset", "watcherdone"]);
diff --git a/third_party/blink/web_tests/external/wpt/webxr/events_session_select.https.html b/third_party/blink/web_tests/external/wpt/webxr/events_session_select.https.html
index b74d5ea..396d6b2 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/events_session_select.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/events_session_select.https.html
@@ -38,6 +38,7 @@
       let input_sources = session.inputSources;
       assert_equals(event.frame.session, session);
       assert_equals(event.inputSource, input_sources[0]);
+      validateSameObject(event);
       tryCallingFrameMethods(event.frame);
     });
   }
@@ -47,6 +48,7 @@
       let input_sources = session.inputSources;
       assert_equals(event.frame.session, session);
       assert_equals(event.inputSource, input_sources[0]);
+      validateSameObject(event);
       tryCallingFrameMethods(event.frame);
     });
     session.dispatchEvent(watcherDone);
@@ -57,10 +59,24 @@
       let input_sources = session.inputSources;
       assert_equals(event.frame.session, session);
       assert_equals(event.inputSource, input_sources[0]);
+      validateSameObject(event);
       tryCallingFrameMethods(event.frame);
     });
   }
 
+  // Verifies that the same object is returned each time attributes are accessed
+  // on an XRInputSoruceEvent, as required by the spec.
+  function validateSameObject(event) {
+    let frame = event.frame;
+    let source = event.inputSource;
+    t.step(() => {
+      assert_equals(frame, event.frame,
+        "XRInputSourceEvent.frame returns the same object.");
+      assert_equals(source, event.inputSource,
+        "XRInputSourceEvent.inputSource returns the same object.");
+    });
+  }
+
   session.addEventListener("selectstart", onSessionSelectStart, false);
   session.addEventListener("selectend", onSessionSelectEnd, false);
   session.addEventListener("select", onSessionSelect, false);
diff --git a/third_party/blink/web_tests/external/wpt/webxr/navigator_xr_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/navigator_xr_sameObject.https.html
new file mode 100644
index 0000000..56cd65c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/navigator_xr_sameObject.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "Navigator.xr meets [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  let xr = navigator.xr;
+
+  return new Promise((resolve) => {
+    // Make sure the navigator.xr object is the same on each frame.
+    session.requestAnimationFrame((time, xrFrame) => {
+      t.step(() => {
+        assert_equals(navigator.xr, xr, "navigator.xr returns the same object");
+      });
+      session.requestAnimationFrame((time, xrFrame) => {
+        t.step(() => {
+          assert_equals(navigator.xr, xr,
+            "naivgator.xr returns the same object");
+        });
+        resolve();
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrFrame_session_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrFrame_session_sameObject.https.html
new file mode 100644
index 0000000..cbbef68
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrFrame_session_sameObject.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRFrame.session meets [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    session.requestAnimationFrame((time, xrFrame) => {
+      let session = xrFrame.session;
+      t.step(() => {
+        assert_equals(session, xrFrame.session,
+          "XRFrame.session returns the same object.");
+      });
+      resolve();
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrInputSource_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrInputSource_sameObject.https.html
new file mode 100644
index 0000000..78240de
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrInputSource_sameObject.https.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRInputSource attributes meet [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    let input_source = fakeDeviceController.simulateInputSourceConnection({
+      handedness: "right",
+      targetRayMode: "tracked-pointer",
+      pointerOrigin: VALID_POINTER_TRANSFORM,
+      gripOrigin: VALID_GRIP_TRANSFORM,
+      profiles: ["foo", "bar"]
+    });
+
+    session.requestAnimationFrame((time, xrFrame) => {
+      let source = session.inputSources[0];
+      let targetRaySpace = source.targetRaySpace;
+      let gripSpace = source.gripSpace;
+      let profiles = source.profiles;
+
+      t.step(() => {
+        assert_not_equals(targetRaySpace, null,
+          "target ray space must not be null");
+        assert_not_equals(gripSpace, null, "grip space must not be null");
+
+        // Make sure [SameObject] attributes actually have the same object
+        // returned each time they are accessed.
+        assert_equals(targetRaySpace, source.targetRaySpace,
+          "XRInputSource.targetRaySpace returns the same object.");
+        assert_equals(gripSpace, source.gripSpace,
+          "XRInputSource.gripSpace returns the same object.");
+        assert_equals(profiles, source.profiles,
+          "XRInputSource.profiles returns the same object.");
+      });
+
+      session.requestAnimationFrame((time, xrFrame) => {
+        // Make sure the attributes still return the same object on the next
+        // frame when nothing has happened that would cause the input source
+        // to be recreated.
+        t.step(() => {
+          assert_equals(targetRaySpace, source.targetRaySpace,
+            "XRInputSource.targetRaySpace returns the same object each frame.");
+          assert_equals(gripSpace, source.gripSpace,
+            "XRInputSource.gripSpace returns the same object each frame.");
+          assert_equals(profiles, source.profiles,
+            "XRInputSource.profiles returns the same object each frame.");
+        });
+
+        resolve();
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrPose_transform_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrPose_transform_sameObject.https.html
new file mode 100644
index 0000000..79eed4c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrPose_transform_sameObject.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRPose.transform meets [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    let input_source = fakeDeviceController.simulateInputSourceConnection({
+      handedness: "right",
+      targetRayMode: "tracked-pointer",
+      pointerOrigin: VALID_POINTER_TRANSFORM,
+      gripOrigin: VALID_GRIP_TRANSFORM,
+      profiles: []
+    });
+
+    session.requestReferenceSpace('local').then((referenceSpace) => {
+      session.requestAnimationFrame((time, xrFrame) => {
+        let source = session.inputSources[0];
+        let input_pose = xrFrame.getPose(source.targetRaySpace, referenceSpace);
+
+        // Make sure that the transform attribute is the same object each time
+        // we access it. This verifies that the XRPose does *not* do something
+        // spec-noncompliant such as creating and returning a new
+        // XRRigidTransform object each time the attribute is accessed.
+        let transform = input_pose.transform;
+        t.step(() => {
+          assert_equals(transform, input_pose.transform,
+            "XRPose.transform returns the same object.");
+        });
+        resolve();
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrRigidTransform_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrRigidTransform_sameObject.https.html
new file mode 100644
index 0000000..d014fe6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrRigidTransform_sameObject.https.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script>
+
+let testName = "XRRigidTransform position and orientation meet [SameObject] requirements";
+
+// xrRigidTransform_inverse.https.html already checks [SameObject] requirement
+// for XRRigidTransform.inverse. It's in a separate test because there are
+// additional constraints around how the inverse attribute should work besides
+// just [SameObject].
+
+let testFunction =
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
+
+  let transform = new XRRigidTransform(
+      { x: -9.0, y: 8.0, z: -7.0 },
+      { x: 6.0, y: -5.0, z: 4.0, w: 3.0 });
+
+  let position = transform.position;
+  let orientation = transform.orientation;
+  t.step(() => {
+    assert_equals(position, transform.position,
+      "XRRigidTransform.position returns the same object.");
+    assert_equals(orientation, transform.orientation,
+      "XRRigidTransform.orientation returns the same object.");
+  });
+
+  resolve();
+});
+
+xr_session_promise_test(testName, testFunction, TRACKED_IMMERSIVE_DEVICE,
+    'immersive-vr');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrSession_end.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrSession_end.https.html
index b91a5b9..e8c078e 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrSession_end.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrSession_end.https.html
@@ -19,6 +19,11 @@
       function onSessionEnd(event) {
         t.step( () => {
           assert_equals(event.session, session);
+
+          let eventSession = event.session;
+          assert_equals(eventSession, event.session,
+            "XRSessionEvent.session returns the same object.");
+
           session.dispatchEvent(watcherDone);
         });
       }
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrSession_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrSession_sameObject.https.html
new file mode 100644
index 0000000..837fa0a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrSession_sameObject.https.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRSession attributes meet [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    let input_source = fakeDeviceController.simulateInputSourceConnection({
+      handedness: "right",
+      targetRayMode: "tracked-pointer",
+      pointerOrigin: VALID_POINTER_TRANSFORM,
+      gripOrigin: VALID_GRIP_TRANSFORM,
+      profiles: ["foo", "bar"]
+    });
+
+    session.requestAnimationFrame((time, xrFrame) => {
+      let renderState = session.renderState;
+      let sources = session.inputSources;
+
+      t.step(() => {
+        assert_not_equals(renderState, null, "renderState must not be null.");
+        assert_not_equals(sources, null, "inputSources must not be null.");
+
+        // Make sure [SameObject] attributes actually have the same object
+        // returned each time they are accessed.
+        assert_equals(renderState, session.renderState,
+          "XRSession.renderState returns the same object.");
+        assert_equals(sources, session.inputSources,
+          "XRSession.inputSources returns the same object.");
+      });
+
+      session.requestAnimationFrame((time, xrFrame) => {
+        t.step(() => {
+          // Make sure the attributes still return the same object on the next
+          // frame.
+          assert_equals(renderState, session.renderState,
+            "XRSession.renderState returns the same object.");
+          assert_equals(sources, session.inputSources,
+            "XRSession.inputSources returns the same object.");
+        });
+
+        // Even though changing handedness on the input source should cause that
+        // source to be re-created, it should not cause the entire
+        // XRInputSourceArray object on XRSession to be re-created.
+        input_source.setHandedness("left");
+        session.requestAnimationFrame((time, xrFrame) => {
+          t.step(() => {
+            assert_equals(renderState, session.renderState,
+              "XRSession.renderState returns the same object.");
+            assert_equals(sources, session.inputSources,
+              "XRSession.inputSources returns the same object.");
+          });
+          resolve();
+        });
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrView_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrView_sameObject.https.html
new file mode 100644
index 0000000..1213bcb1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrView_sameObject.https.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRView attributes meet [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    session.requestReferenceSpace('local').then((referenceSpace) => {
+      session.requestAnimationFrame((time, xrFrame) => {
+        // Make sure that the projectionMatrix and transform attributes on
+        // XRView always return the same object.
+        let viewerPose = xrFrame.getViewerPose(referenceSpace);
+        let view = viewerPose.views[0];
+
+        let transform = view.transform;
+        let projectionMatrix = view.projectionMatrix;
+
+        t.step(() => {
+          assert_equals(transform, view.transform,
+            "XRView.transform returns the same object.");
+          assert_equals(projectionMatrix, view.projectionMatrix,
+            "XRView.projectionMatrix returns the same object.");
+        });
+
+        resolve();
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrViewerPose_views_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrViewerPose_views_sameObject.https.html
new file mode 100644
index 0000000..ec1ee696
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrViewerPose_views_sameObject.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let testName = "XRViewerPose.views meets [SameObject] requirement";
+
+let testFunction = function(session, fakeDeviceController, t) {
+  return new Promise((resolve) => {
+    session.requestReferenceSpace('local').then((referenceSpace) => {
+      session.requestAnimationFrame((time, xrFrame) => {
+        // Make sure that the views attribute is the same object each time we
+        // access it. This verifies that XRViewerPose does *not* do something
+        // spec-noncompliant such as creating and returning a new XRView array
+        // each time the attribute is accessed.
+        let viewerPose = xrFrame.getViewerPose(referenceSpace);
+        let views = viewerPose.views;
+        t.step(() => {
+          assert_equals(viewerPose.views, views,
+            "XRViewerPose.views returns the same object.");
+        });
+
+        resolve();
+      });
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer_sameObject.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer_sameObject.https.html
new file mode 100644
index 0000000..b0f6378
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer_sameObject.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas />
+
+<script>
+
+let testName = "XRWebGLLayer.framebuffer meets [SameObject] requirement";
+
+let testFunction =
+  (session, fakeDeviceController, t, sessionObjects) => new Promise((resolve, reject) => {
+  let layer = new XRWebGLLayer(session, sessionObjects.gl, {});
+  let framebuffer = layer.framebuffer;
+  t.step(() => {
+    assert_equals(framebuffer, layer.framebuffer,
+      "XRWebGLLayer.framebuffer returns the same object.");
+  });
+  resolve();
+});
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+
+</script>
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/cross-origin-opener-policy/popup-same-site-unsafe-allow-outgoing.https-expected.txt
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/html/dom/documents/resource-metadata-management/document-lastModified-01-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/html/dom/documents/resource-metadata-management/document-lastModified-01-expected.txt
deleted file mode 100644
index c7a09337..0000000
--- a/third_party/blink/web_tests/platform/win7/external/wpt/html/dom/documents/resource-metadata-management/document-lastModified-01-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Date returned by lastModified is current at page load assert_approx_equals: expected 1565945123 +/- 2.5 but got 1565948723
-PASS Date returned by lastModified is in the form "MM/DD/YYYY hh:mm:ss".
-FAIL Date returned by lastModified is in the user's local time zone. assert_approx_equals: Hours and minutes should match local time. expected 2723 +/- 2 but got 6323
-FAIL Date returned by lastModified is current after timeout. assert_approx_equals: (initial value was 1565948723) expected 1565945127 +/- 2.5 but got 1565948727
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt
index 1a94897c..04756d5 100644
--- a/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/external/wpt/xhr/responsexml-document-properties-expected.txt
@@ -15,8 +15,8 @@
 PASS cookie
 PASS Test document URL properties after redirect
 PASS Test document URL properties of document with <base> after redirect
-FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565945186 but got 1565948786
-FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565923145000 but got 1565919545000
+FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565984468 but got 1565988068
+FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565962290000 but got 1565958690000
 PASS cookie (after setting it)
 PASS styleSheets should be an object
 PASS implementation should be an object
diff --git a/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt
index 975e209..722ef26c 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt
+++ b/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt
@@ -15,8 +15,8 @@
 PASS cookie
 PASS Test document URL properties after redirect
 PASS Test document URL properties of document with <base> after redirect
-FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565944940 but got 1565948540
-FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565923114000 but got 1565919514000
+FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565984257 but got 1565987857
+FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565962233000 but got 1565958633000
 PASS cookie (after setting it)
 PASS styleSheets should be an object
 PASS implementation should be an object
diff --git a/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/xhr/responsexml-document-properties-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/xhr/responsexml-document-properties-expected.txt
new file mode 100644
index 0000000..62962528
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/xhr/responsexml-document-properties-expected.txt
@@ -0,0 +1,27 @@
+This is a testharness.js-based test.
+PASS domain
+PASS URL
+PASS documentURI
+PASS baseURI
+PASS referrer
+PASS title
+PASS contentType
+PASS readyState
+PASS location
+PASS defaultView
+PASS body
+PASS doctype
+PASS all
+PASS cookie
+PASS Test document URL properties after redirect
+PASS Test document URL properties of document with <base> after redirect
+FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565984068 but got 1565987668
+FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565962225000 but got 1565958625000
+PASS cookie (after setting it)
+PASS styleSheets should be an object
+PASS implementation should be an object
+PASS images should be an object
+PASS forms should be an object
+PASS links should be an object
+Harness: the test ran to completion.
+
diff --git a/third_party/byte_buddy/BUILD.gn b/third_party/byte_buddy/BUILD.gn
index c651ac2..f82160ca 100644
--- a/third_party/byte_buddy/BUILD.gn
+++ b/third_party/byte_buddy/BUILD.gn
@@ -18,11 +18,21 @@
   jar_path = "lib/byte-buddy-agent.jar"
 }
 
+# The current version of //third_party/byte_buddy relies on an older
+# version of dx.
+java_prebuilt("dx_25_0_2_java") {
+  supports_android = true
+  requires_android = true
+  no_build_hooks = true
+  testonly = true
+  jar_path = "android_sdk_build_tools_25_0_2/build-tools/25.0.2/lib/dx.jar"
+}
+
 android_java_prebuilt("byte_buddy_android_java") {
   testonly = true
   enable_bytecode_checks = false
   deps = [
-    "//third_party/android_sdk:dx_25_0_2_java",
+    ":dx_25_0_2_java",
   ]
   proguard_configs = [ "//third_party/byte_buddy/proguard.flags" ]
   jar_path = "lib/byte-buddy-android.jar"
diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py
index 5b87a2f..27ba366 100644
--- a/tools/grit/grit/tclib.py
+++ b/tools/grit/grit/tclib.py
@@ -56,7 +56,7 @@
         # otherwise "EXAMPLE_FOO" splits "EXAMPLE_FOO_NAME" too.
         tags = sorted(tag_map.keys(),
                       key=functools.cmp_to_key(
-                          lambda x, y: len(x) - len(y) or cmp(x, y)),
+                          lambda x, y: len(x) - len(y) or ((x > y) - (x < y))),
                       reverse=True)
         tag_re = '(' + '|'.join(tags) + ')'
 
diff --git a/tools/grit/grit/tool/xmb.py b/tools/grit/grit/tool/xmb.py
index 454bdb25..b821308 100644
--- a/tools/grit/grit/tool/xmb.py
+++ b/tools/grit/grit/tool/xmb.py
@@ -49,8 +49,9 @@
       name: name of the attribute
       value: (unescaped) value of the attribute
     """
+  name = name.encode('utf-8')
   if value:
-    file.write(' %s="%s"' % (name, _XmlEscape(value)))
+    file.write(b' %s="%s"' % (name, _XmlEscape(value)))
 
 
 def _WriteMessage(file, message):
@@ -61,38 +62,38 @@
   preserve_space = presentable_content != _WHITESPACES_REGEX.sub(
       u' ', presentable_content.strip())
 
-  file.write('<msg')
+  file.write(b'<msg')
   _WriteAttribute(file, 'desc', message.GetDescription())
   _WriteAttribute(file, 'id', message.GetId())
   _WriteAttribute(file, 'meaning', message.GetMeaning())
   if preserve_space:
     _WriteAttribute(file, 'xml:space', 'preserve')
-  file.write('>')
+  file.write(b'>')
   if not preserve_space:
-    file.write('\n  ')
+    file.write(b'\n  ')
 
   parts = message.GetContent()
   for part in parts:
     if isinstance(part, tclib.Placeholder):
-      file.write('<ph')
+      file.write(b'<ph')
       _WriteAttribute(file, 'name', part.GetPresentation())
-      file.write('><ex>')
+      file.write(b'><ex>')
       file.write(_XmlEscape(part.GetExample()))
-      file.write('</ex>')
+      file.write(b'</ex>')
       file.write(_XmlEscape(part.GetOriginal()))
-      file.write('</ph>')
+      file.write(b'</ph>')
     else:
       file.write(_XmlEscape(part))
   if not preserve_space:
-    file.write('\n')
-  file.write('</msg>\n')
+    file.write(b'\n')
+  file.write(b'</msg>\n')
 
 
 def WriteXmbFile(file, messages):
   """Writes the given grit.tclib.Message items to the specified open
   file-like object in the XMB format.
   """
-  file.write("""<?xml version="1.0" encoding="UTF-8"?>
+  file.write(b"""<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE messagebundle [
 <!ELEMENT messagebundle (msg)*>
 <!ATTLIST messagebundle class CDATA #IMPLIED>
@@ -118,7 +119,7 @@
 """)
   for message in messages:
     _WriteMessage(file, message)
-  file.write('</messagebundle>')
+  file.write(b'</messagebundle>')
 
 
 class OutputXmb(interface.Tool):
diff --git a/tools/grit/grit/tool/xmb_unittest.py b/tools/grit/grit/tool/xmb_unittest.py
index 0549f79..3c7e92ce 100755
--- a/tools/grit/grit/tool/xmb_unittest.py
+++ b/tools/grit/grit/tool/xmb_unittest.py
@@ -7,6 +7,7 @@
 
 from __future__ import print_function
 
+import io
 import os
 import sys
 if __name__ == '__main__':
@@ -25,7 +26,7 @@
 class XmbUnittest(unittest.TestCase):
   def setUp(self):
     self.res_tree = grd_reader.Parse(
-        StringIO(u'''<?xml version="1.0" encoding="UTF-8"?>
+        io.BytesIO(u'''<?xml version="1.0" encoding="UTF-8"?>
       <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
         <release seq="3">
           <includes>
@@ -50,7 +51,7 @@
           </structures>
         </release>
       </grit>'''.encode('utf-8')), '.')
-    self.xmb_file = StringIO()
+    self.xmb_file = io.BytesIO()
 
   def testNormalOutput(self):
     xmb.OutputXmb().Process(self.res_tree, self.xmb_file)
@@ -63,7 +64,7 @@
     limit_file = StringIO(
       'IDS_BONGOBINGO\nIDS_DOES_NOT_EXIST\nIDS_ALSO_DOES_NOT_EXIST')
     xmb.OutputXmb().Process(self.res_tree, self.xmb_file, limit_file, False)
-    output = self.xmb_file.getvalue()
+    output = self.xmb_file.getvalue().decode('utf-8')
     self.failUnless(output.count('Yibbee'))
     self.failUnless(not output.count('Joi'))
 
@@ -83,7 +84,7 @@
       extra_verbose = False
     tool.o = DummyOpts()
     tool.Process(self.res_tree, self.xmb_file, limit_file, True, dir='.')
-    output = self.xmb_file.getvalue()
+    output = self.xmb_file.getvalue().decode('utf-8')
     self.failUnless(output.count('Joi'))
     self.failUnless(not output.count('Yibbee'))
 
@@ -92,7 +93,7 @@
     os.chdir(util.PathFromRoot('.'))  # so it can find klonk.rc
     self.res_tree.RunGatherers()
     xmb.OutputXmb().Process(self.res_tree, self.xmb_file)
-    output = self.xmb_file.getvalue()
+    output = self.xmb_file.getvalue().decode('utf-8')
     self.failUnless(output.count(
         '<ph name="GOOD_1"><ex>excellent</ex>[GOOD]</ph>'))
 
@@ -104,14 +105,14 @@
     os.chdir(util.PathFromRoot('.'))  # so it can find klonk.rc
     self.res_tree.RunGatherers()
     xmb.OutputXmb().Process(self.res_tree, self.xmb_file)
-    output = self.xmb_file.getvalue()
+    output = self.xmb_file.getvalue().decode('utf-8')
     self.failUnless(output.count('OK ? </msg>'))
 
   def testDisallowedChars(self):
     # Validate that the invalid unicode is not accepted. Since it's not valid,
     # we can't specify it in a string literal, so write as a byte sequence.
-    bad_xml = StringIO()
-    bad_xml.write('''<?xml version="1.0" encoding="UTF-8"?>
+    bad_xml = io.BytesIO()
+    bad_xml.write(b'''<?xml version="1.0" encoding="UTF-8"?>
       <grit latest_public_release="2" source_lang_id="en-US"
             current_release="3" base_dir=".">
         <release seq="3">
@@ -120,7 +121,7 @@
     # UTF-8 corresponding to to \U00110000
     # http://apps.timwhitlock.info/unicode/inspect/hex/110000
     bad_xml.write(b'\xF4\x90\x80\x80')
-    bad_xml.write('''</message>
+    bad_xml.write(b'''</message>
           </messages>
         </release>
       </grit>''')
diff --git a/tools/grit/grit/util.py b/tools/grit/grit/util.py
index 69cc527..d3755f1 100644
--- a/tools/grit/grit/util.py
+++ b/tools/grit/grit/util.py
@@ -8,6 +8,7 @@
 from __future__ import print_function
 
 import codecs
+import io
 import os
 import re
 import shutil
@@ -349,18 +350,18 @@
     body = body.encode('utf-8')
   if base_dir is None:
     base_dir = PathFromRoot('.')
-  lines = ['<?xml version="1.0" encoding="UTF-8"?>']
-  lines.append(('<grit latest_public_release="2" current_release="3" '
-                'source_lang_id="en" base_dir="{}">').format(base_dir))
-  if '<outputs>' in body:
+  lines = [b'<?xml version="1.0" encoding="UTF-8"?>']
+  lines.append(b'<grit latest_public_release="2" current_release="3" '
+               b'source_lang_id="en" base_dir="%s">' % base_dir.encode('utf-8'))
+  if b'<outputs>' in body:
     lines.append(body)
   else:
-    lines.append('  <outputs></outputs>')
-    lines.append('  <release seq="3">')
+    lines.append(b'  <outputs></outputs>')
+    lines.append(b'  <release seq="3">')
     lines.append(body)
-    lines.append('  </release>')
-  lines.append('</grit>')
-  ret = grd_reader.Parse(StringIO('\n'.join(lines)), dir=".")
+    lines.append(b'  </release>')
+  lines.append(b'</grit>')
+  ret = grd_reader.Parse(io.BytesIO(b'\n'.join(lines)), dir='.')
   ret.SetOutputLanguage('en')
   if run_gatherers:
     ret.RunGatherers()
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1af92f08..1a64bc9 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7565,29 +7565,29 @@
 </enum>
 
 <enum name="ChromeColorsInfo">
-  <int value="0" label="OTHER"/>
-  <int value="1" label="Elephant"/>
-  <int value="2" label="Light grey"/>
-  <int value="3" label="Midnight"/>
+  <int value="0" label="Other"/>
+  <int value="1" label="Warm grey"/>
+  <int value="2" label="Cool grey"/>
+  <int value="3" label="Midnight blue"/>
   <int value="4" label="Black"/>
-  <int value="5" label="Beige/White"/>
-  <int value="6" label="Yellow/White"/>
-  <int value="7" label="Green/White"/>
-  <int value="8" label="Light Teal/White"/>
-  <int value="9" label="Light Purple/White"/>
-  <int value="10" label="Pink/White"/>
+  <int value="5" label="Beige and white"/>
+  <int value="6" label="Yellow and white"/>
+  <int value="7" label="Green and white"/>
+  <int value="8" label="Light teal and white"/>
+  <int value="9" label="Light purple and white"/>
+  <int value="10" label="Pink and white"/>
   <int value="11" label="Beige"/>
   <int value="12" label="Orange"/>
-  <int value="13" label="Light Green"/>
-  <int value="14" label="Light Teal"/>
-  <int value="15" label="Light Blue"/>
+  <int value="13" label="Light green"/>
+  <int value="14" label="Light teal"/>
+  <int value="15" label="Light blue"/>
   <int value="16" label="Pink"/>
-  <int value="17" label="Dark Pink/Red"/>
-  <int value="18" label="Dark Red/Orange"/>
-  <int value="19" label="Dark Green"/>
-  <int value="20" label="Dark Teal"/>
-  <int value="21" label="Dark Blue"/>
-  <int value="22" label="Dark Purple"/>
+  <int value="17" label="Dark pink and red"/>
+  <int value="18" label="Dark red and orange"/>
+  <int value="19" label="Dark green"/>
+  <int value="20" label="Dark teal"/>
+  <int value="21" label="Dark blue"/>
+  <int value="22" label="Dark purple"/>
 </enum>
 
 <enum name="ChromeColorsRevertReason">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1bc5c18..8e2dd2740 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -10601,9 +10601,9 @@
 </histogram>
 
 <histogram name="Autofill.ProfileSuggestionsMadeWithFormatter"
-    enum="BooleanCreated" expires_after="2019-08-16">
-  <owner>caitlinfischer@google.com</owner>
-  <owner>chrome-autofill@google.com</owner>
+    enum="BooleanCreated" expires_after="2020-01-16">
+  <owner>battre@chromium.org</owner>
+  <owner>src/components/autofill/OWNERS</owner>
   <summary>
     This metric is recorded when the autofill-use-improved-label-disambiguation
     experiment is enabled and profile suggestions are available. This metric
@@ -37207,9 +37207,7 @@
 
 <histogram
     name="Event.Latency.ScrollBegin.Scrollbar.TimeToScrollUpdateSwapBegin4"
-    units="microseconds" expires_after="never">
-<!-- expires-never: "heartbeat" metric (internal: go/uma-heartbeats) -->
-
+    units="microseconds" expires_after="M85">
   <owner>input-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <owner>dlibby@microsoft.com</owner>
@@ -37432,9 +37430,7 @@
 </histogram>
 
 <histogram name="Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4"
-    units="microseconds" expires_after="never">
-<!-- expires-never: "heartbeat" metric (internal: go/uma-heartbeats) -->
-
+    units="microseconds" expires_after="M85">
   <owner>tdresser@chromium.org</owner>
   <owner>input-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
@@ -37862,9 +37858,7 @@
 
 <histogram
     name="Event.Latency.ScrollUpdate.Scrollbar.TimeToScrollUpdateSwapBegin4"
-    units="microseconds" expires_after="never">
-<!-- expires-never: "heartbeat" metric (internal: go/uma-heartbeats) -->
-
+    units="microseconds" expires_after="M85">
   <owner>input-dev@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <owner>dlibby@microsoft.com</owner>
@@ -95499,9 +95493,7 @@
 </histogram>
 
 <histogram name="PageLoad.PaintTiming.NavigationToFirstPaint" units="ms"
-    expires_after="never">
-<!-- expires-never: "heartbeat" metric (internal: go/uma-heartbeats) -->
-
+    expires_after="2020-08-14">
   <owner>ksakamoto@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
@@ -98784,7 +98776,11 @@
 </histogram>
 
 <histogram name="PasswordProtection.DomFeatureParsing" enum="BooleanSuccess"
-    expires_after="M79">
+    expires_after="M78">
+  <obsolete>
+    Removed in M78. The DOM features always parsed successfully, so this
+    histogram wasn't useful.
+  </obsolete>
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -133041,6 +133037,17 @@
   </summary>
 </histogram>
 
+<histogram name="Stability.iOS.UTE.OSRestartedAfterPreviousSession"
+    enum="BooleanEnabled" expires_after="M82">
+  <owner>eugenebut@chromium.org</owner>
+  <owner>michaeldo@chromium.org</owner>
+  <summary>
+    true if OS was restarted after the previous session. Logged on application
+    launch if the last session terminated in an unclean state. If this is false
+    then UTE was not caused by OS restart or shutdown.
+  </summary>
+</histogram>
+
 <histogram name="Stability.iOS.UTE.OSVersion" enum="VersionComparison"
     expires_after="M82">
   <owner>michaeldo@chromium.org</owner>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 0526c656..45d1983 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -56,6 +56,8 @@
 crbug.com/967809 [ android-webview ] blink_perf.canvas/upload-video-to-texture_RAF.html?RAF [ Skip ]
 crbug.com/978159 [ android-nexus-5x ] blink_perf.canvas/* [ Skip ]
 crbug.com/978159 [ android-nexus-5x android-webview ] blink_perf.canvas/* [ Skip ]
+crbug.com/994912 [ android-webview ] blink_perf.canvas/transferFromImageBitmap_RAF.html?RAF [ Skip ]
+crbug.com/994912 [ android-webview ] blink_perf.canvas/transferFromImageBitmap.html [ Skip ]
 
 # Benchmark: blink_perf.css
 crbug.com/891878 [ android-nexus-5x android-webview ] blink_perf.css/CustomPropertiesVarAlias.html [ Skip ]
diff --git a/ui/gl/gl_image_io_surface_egl.mm b/ui/gl/gl_image_io_surface_egl.mm
index 15db4a1..122b9e4d 100644
--- a/ui/gl/gl_image_io_surface_egl.mm
+++ b/ui/gl/gl_image_io_surface_egl.mm
@@ -39,8 +39,9 @@
       return {GL_RED_INTEGER, GL_UNSIGNED_SHORT};
     case gfx::BufferFormat::RG_88:
       return {GL_RG, GL_UNSIGNED_BYTE};
+    case gfx::BufferFormat::BGRX_8888:
+      return {GL_RGB, GL_UNSIGNED_BYTE};
     case gfx::BufferFormat::BGRA_8888:
-    case gfx::BufferFormat::BGRX_8888:  // See https://crbug.com/595948.
     case gfx::BufferFormat::RGBA_8888:
       return {GL_BGRA_EXT, GL_UNSIGNED_BYTE};
     case gfx::BufferFormat::RGBA_F16: