diff --git a/.gn b/.gn
index c1a1113..eaf210ef 100644
--- a/.gn
+++ b/.gn
@@ -85,7 +85,7 @@
   "//chrome/app/*",
   "//chrome/app_shim/*",
 
-  #"//chrome/browser/android/*",  # Only metrics and vr have errors.
+  #"//chrome/browser/android/*",  # Only vr has errors. https://crbug.com/871623
   "//chrome/browser/android/accessibility/*",
   "//chrome/browser/android/autofill_assistant/*",
   "//chrome/browser/android/bookmarks/*",
@@ -119,6 +119,7 @@
   "//chrome/browser/android/history_report/*",
   "//chrome/browser/android/instantapps/*",
   "//chrome/browser/android/locale/*",
+  "//chrome/browser/android/metrics/*",
   "//chrome/browser/android/mojo/*",
   "//chrome/browser/android/net/*",
   "//chrome/browser/android/ntp/*",
diff --git a/BUILD.gn b/BUILD.gn
index 45b912d..2543a3a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -146,8 +146,6 @@
       "//third_party/cacheinvalidation:cacheinvalidation_unittests",
       "//third_party/pdfium/samples:pdfium_test",
       "//third_party/webrtc/rtc_tools:frame_analyzer",
-      "//tools/battor_agent",
-      "//tools/battor_agent:battor_agent_unittests",
       "//tools/perf/clear_system_cache",
       "//tools/traffic_annotation/auditor:traffic_annotation_auditor",
       "//tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests",
@@ -952,7 +950,7 @@
       "//third_party/WebKit/LayoutTests/",
       "//third_party/blink/perf_tests/",
       "//third_party/blink/tools/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
     ]
 
     if (is_win) {
diff --git a/DEPS b/DEPS
index b7332821..7c404d9 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '057c39025a93b03bc9b9e435d1a4685d4bbd97e0',
+  'skia_revision': '8af4c40014e3db976bc7da21fbc9c991d68b109b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'f43cb96ec2213a32cb3a2fbd528a6ee41de910df',
+  'v8_revision': '4fe3de13fc5c2592559bb5e49e1a81a6d09a2efd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -117,7 +117,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': 'c93eeaab15269253593e929abce8cdfea52242ef',
+  'angle_revision': 'c43cdad25851a5602698fedbf1a96bf5673d69a2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'f90277e7f4bd99bba419b53341c6c7bdca478eed',
+  'pdfium_revision': '60627d6eafd025dde711e532eee6866840c04bef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -153,7 +153,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'a87b168e08d3b69241b7f185e5ee3c96ed8bf478',
+  'nacl_revision': '96088f46727b75b2f6a24e1b62e5cc59ddb4612d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -165,7 +165,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '9aa552b15750a6d530b34009589ad5d9b4d4ec83',
+  'catapult_revision': 'bca7d20ad76a1d8c3e594443e9100ba4999a266c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -552,7 +552,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '94ec5e5e83b994b7361184ba24f17bdc645575c6',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5570c88a3dce00f73a26cb5e60033f54949355d6',
       'condition': 'checkout_linux',
   },
 
@@ -925,7 +925,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '964e15665fbc3108deef40af2f07b515173d7401',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '74182d1df594d4b007526412d2a46a87a7f85f21',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1047,7 +1047,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '8e5014a3925eb070aca00fcff0aa9c36fd30fb3b',
+    Var('webrtc_git') + '/src.git' + '@' + '5f0ce99c04eb18313dd24b3dc31cc6246496d6d5',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 04298f7c..fd7369cf 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -75,17 +75,16 @@
 
 AwBrowserContext* g_browser_context = NULL;
 
-std::unique_ptr<net::ProxyConfigService> CreateProxyConfigService() {
-  std::unique_ptr<net::ProxyConfigService> config_service =
-      net::ProxyResolutionService::CreateSystemProxyConfigService(
-          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+std::unique_ptr<net::ProxyConfigServiceAndroid> CreateProxyConfigService() {
+  std::unique_ptr<net::ProxyConfigServiceAndroid> config_service_android =
+      std::make_unique<net::ProxyConfigServiceAndroid>(
+          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
+          base::ThreadTaskRunnerHandle::Get());
 
   // TODO(csharrison) Architect the wrapper better so we don't need a cast for
   // android ProxyConfigServices.
-  net::ProxyConfigServiceAndroid* android_config_service =
-      static_cast<net::ProxyConfigServiceAndroid*>(config_service.get());
-  android_config_service->set_exclude_pac_url(true);
-  return config_service;
+  config_service_android->set_exclude_pac_url(true);
+  return config_service_android;
 }
 
 std::unique_ptr<AwSafeBrowsingWhitelistManager>
diff --git a/android_webview/browser/aw_contents_statics.cc b/android_webview/browser/aw_contents_statics.cc
index 1bee668..6f9169e 100644
--- a/android_webview/browser/aw_contents_statics.cc
+++ b/android_webview/browser/aw_contents_statics.cc
@@ -130,4 +130,29 @@
   AwURLRequestContextGetter::set_check_cleartext_permitted(permitted);
 }
 
+// static
+void JNI_AwContentsStatics_SetProxyOverride(
+    JNIEnv* env,
+    const JavaParamRef<jclass>&,
+    const base::android::JavaParamRef<jstring>& jhost,
+    jint port,
+    const base::android::JavaParamRef<jobjectArray>& jexclusion_list) {
+  std::string host;
+  base::android::ConvertJavaStringToUTF8(env, jhost, &host);
+  std::vector<std::string> exclusion_list;
+  base::android::AppendJavaStringArrayToStringVector(env, jexclusion_list,
+                                                     &exclusion_list);
+
+  AwBrowserContext::GetDefault()->GetAwURLRequestContext()->SetProxyOverride(
+      host, port, exclusion_list);
+}
+
+// static
+void JNI_AwContentsStatics_ClearProxyOverride(JNIEnv* env,
+                                              const JavaParamRef<jclass>&) {
+  AwBrowserContext::GetDefault()
+      ->GetAwURLRequestContext()
+      ->ClearProxyOverride();
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_permission_manager.cc b/android_webview/browser/aw_permission_manager.cc
index f1f222e..249176a1 100644
--- a/android_webview/browser/aw_permission_manager.cc
+++ b/android_webview/browser/aw_permission_manager.cc
@@ -448,8 +448,8 @@
 
 int AwPermissionManager::SubscribePermissionStatusChange(
     PermissionType permission,
+    content::RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(PermissionStatus)>& callback) {
   return content::PermissionController::kNoPendingOperation;
 }
diff --git a/android_webview/browser/aw_permission_manager.h b/android_webview/browser/aw_permission_manager.h
index 06c94e783..d6ab44a 100644
--- a/android_webview/browser/aw_permission_manager.h
+++ b/android_webview/browser/aw_permission_manager.h
@@ -52,8 +52,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index 0b25146..9d28b87 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -51,6 +51,7 @@
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_util.h"
 #include "net/net_buildflags.h"
+#include "net/proxy_resolution/proxy_config_service_android.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/socket/next_proto.h"
 #include "net/ssl/channel_id_service.h"
@@ -205,7 +206,7 @@
 AwURLRequestContextGetter::AwURLRequestContextGetter(
     const base::FilePath& cache_path,
     const base::FilePath& channel_id_path,
-    std::unique_ptr<net::ProxyConfigService> config_service,
+    std::unique_ptr<net::ProxyConfigServiceAndroid> config_service,
     PrefService* user_pref_service,
     net::NetLog* net_log)
     : cache_path_(cache_path),
@@ -421,4 +422,15 @@
       auth_android_negotiate_account_type_.GetValue());
 }
 
+void AwURLRequestContextGetter::SetProxyOverride(
+    const std::string& host,
+    int port,
+    const std::vector<std::string>& exclusion_list) {
+  proxy_config_service_->SetProxyOverride(host, port, exclusion_list);
+}
+
+void AwURLRequestContextGetter::ClearProxyOverride() {
+  proxy_config_service_->ClearProxyOverride();
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/net/aw_url_request_context_getter.h b/android_webview/browser/net/aw_url_request_context_getter.h
index e7f331f9..792c0de 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.h
+++ b/android_webview/browser/net/aw_url_request_context_getter.h
@@ -27,6 +27,7 @@
 class HttpAuthPreferences;
 class HttpUserAgentSettings;
 class NetLog;
+class ProxyConfigServiceAndroid;
 class ProxyConfigService;
 class URLRequestContext;
 class URLRequestJobFactory;
@@ -39,7 +40,7 @@
   AwURLRequestContextGetter(
       const base::FilePath& cache_path,
       const base::FilePath& channel_id_path,
-      std::unique_ptr<net::ProxyConfigService> config_service,
+      std::unique_ptr<net::ProxyConfigServiceAndroid> config_service,
       PrefService* pref_service,
       net::NetLog* net_log);
 
@@ -51,6 +52,12 @@
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override;
 
+  // Methods to set and clear proxy override
+  void SetProxyOverride(const std::string& host,
+                        int port,
+                        const std::vector<std::string>& exclusion_list);
+  void ClearProxyOverride();
+
  private:
   friend class AwBrowserContext;
   friend class AwURLRequestContextGetterTest;
@@ -81,7 +88,7 @@
   const base::FilePath channel_id_path_;
 
   net::NetLog* net_log_;
-  std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
+  std::unique_ptr<net::ProxyConfigServiceAndroid> proxy_config_service_;
   std::unique_ptr<net::URLRequestJobFactory> job_factory_;
   std::unique_ptr<net::HttpUserAgentSettings> http_user_agent_settings_;
   std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
diff --git a/android_webview/browser/net/aw_url_request_context_getter_unittest.cc b/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
index 3b77941..eb990c8 100644
--- a/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter_unittest.cc
@@ -16,6 +16,7 @@
 #include "net/base/net_errors.h"
 #include "net/log/net_log.h"
 #include "net/proxy_resolution/proxy_config_service.h"
+#include "net/proxy_resolution/proxy_config_service_android.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/ssl/ssl_config.h"
 #include "net/ssl/ssl_config_service.h"
@@ -57,12 +58,16 @@
     android_webview::AwURLRequestContextGetter::RegisterPrefs(
         pref_service_->registry());
 
-    getter_ = base::MakeRefCounted<android_webview::AwURLRequestContextGetter>(
-        temp_dir_.GetPath(), temp_dir_.GetPath().AppendASCII("ChannelID"),
+    std::unique_ptr<net::ProxyConfigServiceAndroid> config_service_android;
+    config_service_android.reset(static_cast<net::ProxyConfigServiceAndroid*>(
         net::ProxyResolutionService::CreateSystemProxyConfigService(
             content::BrowserThread::GetTaskRunnerForThread(
-                content::BrowserThread::IO)),
-        pref_service_.get(), &net_log_);
+                content::BrowserThread::IO))
+            .release()));
+
+    getter_ = base::MakeRefCounted<android_webview::AwURLRequestContextGetter>(
+        temp_dir_.GetPath(), temp_dir_.GetPath().AppendASCII("ChannelID"),
+        std::move(config_service_android), pref_service_.get(), &net_log_);
 
     // AwURLRequestContextGetter implicitly depends on having protocol handlers
     // provided for url::kBlobScheme, url::kFileSystemScheme, and
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/SharedStatics.java b/android_webview/glue/java/src/com/android/webview/chromium/SharedStatics.java
index 656c455..7fe5fbb 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/SharedStatics.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/SharedStatics.java
@@ -117,4 +117,13 @@
         return ThreadUtils.runOnUiThreadBlockingNoException(
                 () -> AwContentsStatics.getSafeBrowsingPrivacyPolicyUrl());
     }
+
+    public void setProxyOverride(String host, int port, String[] exclusionList) {
+        ThreadUtils.runOnUiThread(
+                () -> AwContentsStatics.setProxyOverride(host, port, exclusionList));
+    }
+
+    public void clearProxyOverride() {
+        ThreadUtils.runOnUiThread(() -> AwContentsStatics.clearProxyOverride());
+    }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
index 2215bf06..6a12a9c 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
@@ -120,6 +120,14 @@
         nativeSetCheckClearTextPermitted(permitted);
     }
 
+    public static void setProxyOverride(String host, int port, String[] exclusionList) {
+        nativeSetProxyOverride(host, port, exclusionList);
+    }
+
+    public static void clearProxyOverride() {
+        nativeClearProxyOverride();
+    }
+
     /**
      * Return the first substring consisting of the address of a physical location.
      * @see {@link android.webkit.WebView#findAddress(String)}
@@ -146,4 +154,7 @@
     private static native void nativeSetSafeBrowsingWhitelist(
             String[] urls, Callback<Boolean> callback);
     private static native void nativeSetCheckClearTextPermitted(boolean permitted);
+    private static native void nativeSetProxyOverride(
+            String host, int port, String[] exclusionList);
+    private static native void nativeClearProxyOverride();
 }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/StaticsBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/StaticsBoundaryInterface.java
index d60a60dd..b3b5aac 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/StaticsBoundaryInterface.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/StaticsBoundaryInterface.java
@@ -17,4 +17,6 @@
     void initSafeBrowsing(Context context, ValueCallback<Boolean> callback);
     void setSafeBrowsingWhitelist(List<String> hosts, ValueCallback<Boolean> callback);
     Uri getSafeBrowsingPrivacyPolicyUrl();
+    void setProxyOverride(String host, int port, String[] exclusionList);
+    void clearProxyOverride();
 }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
index a214a6fd..5092bbe 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -124,4 +124,8 @@
 
     // WebViewCompat.getWebChromeClient
     public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
+
+    // WebViewCompat.setProxyOverride
+    // WebViewCompat.clearProxyOverride
+    public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
 }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
index ffc88c4..76913c7e 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -62,7 +62,8 @@
                     Features.POST_WEB_MESSAGE,
                     Features.WEB_MESSAGE_CALLBACK_ON_MESSAGE,
                     Features.GET_WEB_VIEW_CLIENT,
-                    Features.GET_WEB_CHROME_CLIENT
+                    Features.GET_WEB_CHROME_CLIENT,
+                    Features.PROXY_OVERRIDE
             };
     // clang-format on
 
@@ -110,6 +111,16 @@
         public Uri getSafeBrowsingPrivacyPolicyUrl() {
             return mSharedStatics.getSafeBrowsingPrivacyPolicyUrl();
         }
+
+        @Override
+        public void setProxyOverride(String host, int port, String[] exclusionList) {
+            mSharedStatics.setProxyOverride(host, port, exclusionList);
+        }
+
+        @Override
+        public void clearProxyOverride() {
+            mSharedStatics.clearProxyOverride();
+        }
     }
 
     @Override
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e47786d..9ad989d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -263,7 +263,7 @@
     "network_connect_delegate_mus.h",
     "new_window_controller.h",
     "note_taking_controller.h",
-    "pointer_watcher_adapter_classic.h",
+    "pointer_watcher_adapter.h",
     "policy/policy_recommendation_restorer.h",
     "root_window_controller.h",
     "root_window_settings.h",
@@ -906,7 +906,7 @@
     "network_connect_delegate_mus.cc",
     "new_window_controller.cc",
     "note_taking_controller.cc",
-    "pointer_watcher_adapter_classic.cc",
+    "pointer_watcher_adapter.cc",
     "policy/policy_recommendation_restorer.cc",
     "root_window_controller.cc",
     "root_window_settings.cc",
@@ -1781,7 +1781,7 @@
     "metrics/user_metrics_recorder_unittest.cc",
     "multi_device_setup/multi_device_notification_presenter_unittest.cc",
     "mus_property_mirror_ash_unittest.cc",
-    "pointer_watcher_adapter_classic_unittest.cc",
+    "pointer_watcher_adapter_unittest.cc",
     "policy/policy_recommendation_restorer_unittest.cc",
     "root_window_controller_unittest.cc",
     "rotator/screen_rotation_animation_unittest.cc",
@@ -1818,8 +1818,8 @@
     "system/date/system_info_default_view_unittest.cc",
     "system/enterprise/tray_enterprise_unittest.cc",
     "system/flag_warning/flag_warning_tray_unittest.cc",
-    "system/ime/tray_ime_chromeos_unittest.cc",
     "system/ime/ime_feature_pod_controller_unittest.cc",
+    "system/ime/tray_ime_chromeos_unittest.cc",
     "system/ime_menu/ime_menu_tray_unittest.cc",
     "system/keyboard_brightness/tray_keyboard_brightness_unittest.cc",
     "system/media_security/multi_profile_media_tray_item_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 84aad11..12749e5 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -653,7 +653,7 @@
     EXPECT_TRUE(ProcessInController(
         ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
     EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+        ProcessInController(ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
     EXPECT_TRUE(ProcessInController(ui::Accelerator(
         ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
 
@@ -663,7 +663,7 @@
         ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
     EXPECT_EQ(1, delegate->handle_take_screenshot_count());
     EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+        ProcessInController(ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
     EXPECT_EQ(2, delegate->handle_take_screenshot_count());
     EXPECT_TRUE(ProcessInController(ui::Accelerator(
         ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
@@ -909,9 +909,9 @@
 
   // Others are not reserved nor preferred
   EXPECT_FALSE(GetController()->IsReserved(
-      ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+      ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
   EXPECT_FALSE(GetController()->IsPreferred(
-      ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+      ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
   EXPECT_FALSE(
       GetController()->IsReserved(ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE)));
   EXPECT_FALSE(
@@ -1119,7 +1119,7 @@
     EXPECT_TRUE(ProcessInController(
         ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
     EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+        ProcessInController(ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
     EXPECT_TRUE(ProcessInController(ui::Accelerator(
         ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
     delegate->set_can_take_screenshot(true);
@@ -1128,7 +1128,7 @@
         ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
     EXPECT_EQ(1, delegate->handle_take_screenshot_count());
     EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
+        ProcessInController(ui::Accelerator(ui::VKEY_SNAPSHOT, ui::EF_NONE)));
     EXPECT_EQ(2, delegate->handle_take_screenshot_count());
     EXPECT_TRUE(ProcessInController(ui::Accelerator(
         ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc
index 5c26a67..85d17bc 100644
--- a/ash/accelerators/accelerator_filter_unittest.cc
+++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -35,10 +35,11 @@
 
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
   // AcceleratorController calls ScreenshotDelegate::HandleTakeScreenshot() when
-  // VKEY_PRINT is pressed. See kAcceleratorData[] in accelerator_controller.cc.
-  generator.PressKey(ui::VKEY_PRINT, 0);
+  // VKEY_SNAPSHOT is pressed. See kAcceleratorData[] in
+  // accelerator_controller.cc.
+  generator.PressKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(1, delegate->handle_take_screenshot_count());
-  generator.ReleaseKey(ui::VKEY_PRINT, 0);
+  generator.ReleaseKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(1, delegate->handle_take_screenshot_count());
 }
 
@@ -55,9 +56,9 @@
   // AcceleratorFilter should ignore the key events since the root window is
   // not focused.
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
-  generator.PressKey(ui::VKEY_PRINT, 0);
+  generator.PressKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(0, delegate->handle_take_screenshot_count());
-  generator.ReleaseKey(ui::VKEY_PRINT, 0);
+  generator.ReleaseKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(0, delegate->handle_take_screenshot_count());
 
   // Reset window before |test_delegate| gets deleted.
@@ -70,16 +71,16 @@
   EXPECT_EQ(0, delegate->handle_take_screenshot_count());
 
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
-  generator.PressKey(ui::VKEY_PRINT, 0);
+  generator.PressKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(1, delegate->handle_take_screenshot_count());
-  generator.ReleaseKey(ui::VKEY_PRINT, 0);
+  generator.ReleaseKey(ui::VKEY_SNAPSHOT, 0);
   EXPECT_EQ(1, delegate->handle_take_screenshot_count());
 
   // Check if AcceleratorFilter ignores the mask for Caps Lock. Note that there
   // is no ui::EF_ mask for Num Lock.
-  generator.PressKey(ui::VKEY_PRINT, ui::EF_CAPS_LOCK_ON);
+  generator.PressKey(ui::VKEY_SNAPSHOT, ui::EF_CAPS_LOCK_ON);
   EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-  generator.ReleaseKey(ui::VKEY_PRINT, ui::EF_CAPS_LOCK_ON);
+  generator.ReleaseKey(ui::VKEY_SNAPSHOT, ui::EF_CAPS_LOCK_ON);
   EXPECT_EQ(2, delegate->handle_take_screenshot_count());
 }
 
diff --git a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
index c89e71d..9055584 100644
--- a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
+++ b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
@@ -155,7 +155,7 @@
   EXPECT_EQ(0, screenshot_delegate->handle_take_screenshot_count());
   SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, false, false);
   EXPECT_EQ(1, screenshot_delegate->handle_take_screenshot_count());
-  SendKeyPressSync(ui::VKEY_PRINT, false, false, false);
+  SendKeyPressSync(ui::VKEY_SNAPSHOT, false, false, false);
   EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
   SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, true, false);
   EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
diff --git a/ash/accelerators/accelerator_table_unittest.cc b/ash/accelerators/accelerator_table_unittest.cc
index 342e11d..5c7002f 100644
--- a/ash/accelerators/accelerator_table_unittest.cc
+++ b/ash/accelerators/accelerator_table_unittest.cc
@@ -16,12 +16,11 @@
 
 namespace {
 
-// The number of non-Search-based accelerators as of 2018-04-30.
-constexpr int kNonSearchAcceleratorsNum = 88;
-// The hash of non-Search-based accelerators as of 2018-04-30.
-// See HashAcceleratorData().
+// The number of non-Search-based accelerators.
+constexpr int kNonSearchAcceleratorsNum = 89;
+// The hash of non-Search-based accelerators. See HashAcceleratorData().
 constexpr char kNonSearchAcceleratorsHash[] =
-    "06096f5c3177fd99f7c30cfbf4b7d635";
+    "1da4d0dbc648ec0f008837da1066599e";
 
 struct Cmp {
   bool operator()(const AcceleratorData& lhs, const AcceleratorData& rhs) {
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 1414f2a..5c54238 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -412,12 +412,18 @@
 void AppListControllerImpl::UpdateYPositionAndOpacity(
     int y_position_in_screen,
     float background_opacity) {
+  // Avoid changing app list opacity and position when homecher is enabled.
+  if (IsHomeLauncherEnabledInTabletMode())
+    return;
   presenter_.UpdateYPositionAndOpacity(y_position_in_screen,
                                        background_opacity);
 }
 
 void AppListControllerImpl::EndDragFromShelf(
     app_list::AppListViewState app_list_state) {
+  // Avoid dragging app list when homecher is enabled.
+  if (IsHomeLauncherEnabledInTabletMode())
+    return;
   presenter_.EndDragFromShelf(app_list_state);
 }
 
@@ -461,8 +467,14 @@
 
 void AppListControllerImpl::OnTabletModeStarted() {
   if (IsVisible()) {
-    presenter_.GetView()->OnTabletModeChanged(true);
-    return;
+    if (!presenter_.is_animating_to_close()) {
+      presenter_.GetView()->OnTabletModeChanged(true);
+      return;
+    }
+
+    // The launcher is running close animation, so close it immediately before
+    // reshow the launcher in tablet mode.
+    presenter_.GetView()->GetWidget()->CloseNow();
   }
 
   if (!is_home_launcher_enabled_ || !display::Display::HasInternalDisplay())
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index 3732d7b2c..17533ae 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -10,6 +10,7 @@
 #include "ash/app_list/views/app_list_main_view.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/search_box_view.h"
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "ash/public/cpp/ash_switches.h"
@@ -1491,4 +1492,82 @@
   EXPECT_FALSE(root_window_controller->IsContextMenuShown());
 }
 
+// Tests app list visibility when switching to tablet mode during dragging from
+// shelf.
+TEST_F(AppListPresenterDelegateHomeLauncherTest,
+       SwitchToTabletModeDuringDraggingFromShelf) {
+  UpdateDisplay("1080x900");
+  GetAppListTestHelper()->CheckVisibility(false);
+
+  // Drag from the shelf to show the app list.
+  ui::test::EventGenerator* generator = GetEventGenerator();
+  const int x = 540;
+  const int closed_y = 890;
+  const int fullscreen_y = 0;
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->PressTouch();
+  generator->MoveTouch(gfx::Point(x, fullscreen_y));
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  // Drag to shelf to close app list.
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(false);
+
+  // Drag from the shelf to show the app list.
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->PressTouch();
+  generator->MoveTouch(gfx::Point(x, fullscreen_y));
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  // Switch to tablet mode.
+  EnableTabletMode(true);
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  // Drag to shelf to try to close app list.
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(true);
+}
+
+// Tests app list visibility when switching to tablet mode during dragging to
+// close app list.
+TEST_F(AppListPresenterDelegateHomeLauncherTest,
+       SwitchToTabletModeDuringDraggingToClose) {
+  UpdateDisplay("1080x900");
+
+  // Open app list.
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  // Drag to shelf to close app list.
+  ui::test::EventGenerator* generator = GetEventGenerator();
+  const int x = 540;
+  const int peeking_height =
+      900 - app_list::AppListConfig::instance().peeking_app_list_height();
+  const int closed_y = 890;
+  generator->MoveTouch(gfx::Point(x, peeking_height));
+  generator->PressTouch();
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(false);
+
+  // Open app list.
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  // Drag to shelf to close app list, meanwhile switch to tablet mode.
+  generator->MoveTouch(gfx::Point(x, peeking_height));
+  generator->PressTouch();
+  generator->MoveTouch(gfx::Point(x, peeking_height + 10));
+  EnableTabletMode(true);
+  generator->MoveTouch(gfx::Point(x, closed_y));
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(true);
+}
+
 }  // namespace ash
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index c804f6f5..9d33cb47 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -253,6 +253,7 @@
   gfx::Transform transform;
   transform.Translate(-offset.x(), -offset.y());
   layer->SetTransform(transform);
+  is_animating_to_close_ = true;
 
   {
     ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
@@ -318,10 +319,12 @@
 // AppListPresenterImpl, ui::ImplicitAnimationObserver implementation:
 
 void AppListPresenterImpl::OnImplicitAnimationsCompleted() {
-  if (is_visible_)
+  if (is_visible_) {
     view_->GetWidget()->Activate();
-  else
+  } else {
     view_->GetWidget()->Close();
+    is_animating_to_close_ = false;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/app_list/presenter/app_list_presenter_impl.h b/ash/app_list/presenter/app_list_presenter_impl.h
index 598e7071..0ce3a83 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.h
+++ b/ash/app_list/presenter/app_list_presenter_impl.h
@@ -84,6 +84,8 @@
   // Passes a MouseWheelEvent from the shelf to the AppListView.
   void ProcessMouseWheelOffset(int y_scroll_offset);
 
+  bool is_animating_to_close() const { return is_animating_to_close_; }
+
  private:
   // Sets the app list view and attempts to show it.
   void SetView(AppListView* view);
@@ -151,6 +153,9 @@
   bool last_visible_ = false;
   int64_t last_display_id_ = display::kInvalidDisplayId;
 
+  // True if app list is running close animation.
+  bool is_animating_to_close_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(AppListPresenterImpl);
 };
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 2313117..c549ccd1 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -1024,7 +1024,8 @@
       event->SetHandled();
       break;
     case ui::ET_GESTURE_SCROLL_UPDATE:
-      if (is_side_shelf_)
+      // Avoid scrolling events for the app list in tablet mode.
+      if (is_side_shelf_ || IsHomeLauncherEnabledInTabletMode())
         return;
       SetIsInDrag(true);
       last_fling_velocity_ = event->details().scroll_y();
@@ -1034,7 +1035,8 @@
     case ui::ET_GESTURE_END:
       if (!is_in_drag_)
         break;
-      if (is_side_shelf_)
+      // Avoid scrolling events for the app list in tablet mode.
+      if (is_side_shelf_ || IsHomeLauncherEnabledInTabletMode())
         return;
       SetIsInDrag(false);
       EndDrag(event->location());
@@ -1115,6 +1117,18 @@
       return;
     }
 
+    if (is_in_drag_) {
+      SetIsInDrag(false);
+      DraggingLayout();
+    }
+
+    // Set fullscreen state. When current state is fullscreen, we still need to
+    // set it again because app list may be in dragging.
+    SetState(app_list_state_ == AppListViewState::HALF ||
+                     app_list_state_ == AppListViewState::FULLSCREEN_SEARCH
+                 ? AppListViewState::FULLSCREEN_SEARCH
+                 : AppListViewState::FULLSCREEN_ALL_APPS);
+
     // Put app list window in corresponding container based on whether the
     // tablet mode is enabled.
     aura::Window* window = GetWidget()->GetNativeWindow();
@@ -1131,6 +1145,8 @@
     // Update background blur.
     if (is_background_blur_enabled_)
       app_list_background_shield_->layer()->SetBackgroundBlur(0);
+
+    return;
   }
 
   if (is_tablet_mode_ && !is_fullscreen()) {
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 5e1a98dc..a1fc57a 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -218,7 +218,7 @@
         Braille and ChromeVox are enabled
       </message>
       <message name="IDS_ASH_STATUS_TRAY_USER_INFO_ACCESSIBILITY" desc="The accessibility string used for an item in user chooser that tells the user name and the mail address.">
-        <ph name="USERNAME">$1<ex>Jane Doe</ex></ph> <ph name="MAIL">$2<ex>janedoe@example.com</ex></ph>
+        <ph name="USERNAME">$1<ex>Jane Doe</ex></ph> (<ph name="MAIL">$2<ex>janedoe@example.com</ex></ph>)
       </message>
       <message name="IDS_ASH_STATUS_TRAY_SIGN_OUT" desc="The label used for the button in the status tray to sign out of the system. Should not exceed about 20 latin characters. Overflowed text is truncated with ellipsis.">
         Sign out
diff --git a/ash/frame/detached_title_area_renderer.cc b/ash/frame/detached_title_area_renderer.cc
index cc6f1dc..0d8fea5b 100644
--- a/ash/frame/detached_title_area_renderer.cc
+++ b/ash/frame/detached_title_area_renderer.cc
@@ -61,7 +61,9 @@
 void CreateHeaderView(views::Widget* frame,
                       views::Widget* detached_widget,
                       Source source) {
-  HeaderView* header_view = new HeaderView(frame);
+  HeaderView* header_view = new HeaderView(
+      frame, source == Source::CLIENT ? mojom::WindowStyle::BROWSER
+                                      : mojom::WindowStyle::DEFAULT);
   if (source == Source::CLIENT) {
     // HeaderView behaves differently when the widget it is associated with is
     // fullscreen (HeaderView is normally the
diff --git a/ash/login/ui/scrollable_users_list_view.cc b/ash/login/ui/scrollable_users_list_view.cc
index c65b3ed..63c205d 100644
--- a/ash/login/ui/scrollable_users_list_view.cc
+++ b/ash/login/ui/scrollable_users_list_view.cc
@@ -258,8 +258,8 @@
   SetBackgroundColor(SK_ColorTRANSPARENT);
   set_draw_overflow_indicator(false);
 
-  scroll_bar_ = new ScrollBar(false);
-  SetVerticalScrollBar(scroll_bar_);
+  vertical_scroll_bar_ = new ScrollBar(false);
+  SetVerticalScrollBar(vertical_scroll_bar_);
   SetHorizontalScrollBar(new ScrollBar(true));
 
   hover_notifier_ = std::make_unique<HoverNotifier>(
@@ -303,8 +303,8 @@
   ScrollView::Layout();
 
   // Update scrollbar visibility.
-  if (scroll_bar_)
-    scroll_bar_->SetThumbVisible(IsMouseHovered());
+  if (vertical_scroll_bar_)
+    vertical_scroll_bar_->SetThumbVisible(IsMouseHovered());
 }
 
 void ScrollableUsersListView::OnPaintBackground(gfx::Canvas* canvas) {
@@ -321,28 +321,35 @@
   // Only draw a gradient if the wallpaper is blurred. Otherwise, draw a rounded
   // rectangle.
   if (ash::Shell::Get()->wallpaper_controller()->IsWallpaperBlurred()) {
-    // Draws symmetrical linear gradient at the top and bottom of the view.
-    SkScalar view_height = render_bounds.height();
-    SkScalar gradient_height = gradient_params_.height;
-    if (gradient_height == 0)
-      gradient_height = view_height;
-
-    // Start and end point of the drawing in view space.
-    SkPoint in_view_coordinates[2] = {SkPoint(),
-                                      SkPoint::Make(0.f, view_height)};
-    // Positions of colors to create gradient define in 0 to 1 range.
-    SkScalar top_gradient_end = gradient_height / view_height;
-    SkScalar bottom_gradient_start = 1.f - top_gradient_end;
-    SkScalar color_positions[4] = {0.f, top_gradient_end, bottom_gradient_start,
-                                   1.f};
-    SkColor colors[4] = {gradient_params_.color_from, gradient_params_.color_to,
-                         gradient_params_.color_to,
-                         gradient_params_.color_from};
-
     cc::PaintFlags flags;
-    flags.setShader(cc::PaintShader::MakeLinearGradient(
-        in_view_coordinates, colors, color_positions, 4,
-        SkShader::kClamp_TileMode));
+
+    // Only draw a gradient if the content can be scrolled.
+    if (vertical_scroll_bar_->visible()) {
+      // Draws symmetrical linear gradient at the top and bottom of the view.
+      SkScalar view_height = render_bounds.height();
+      SkScalar gradient_height = gradient_params_.height;
+      if (gradient_height == 0)
+        gradient_height = view_height;
+
+      // Start and end point of the drawing in view space.
+      SkPoint in_view_coordinates[2] = {SkPoint(),
+                                        SkPoint::Make(0.f, view_height)};
+      // Positions of colors to create gradient define in 0 to 1 range.
+      SkScalar top_gradient_end = gradient_height / view_height;
+      SkScalar bottom_gradient_start = 1.f - top_gradient_end;
+      SkScalar color_positions[4] = {0.f, top_gradient_end,
+                                     bottom_gradient_start, 1.f};
+      SkColor colors[4] = {gradient_params_.color_from,
+                           gradient_params_.color_to, gradient_params_.color_to,
+                           gradient_params_.color_from};
+
+      flags.setShader(cc::PaintShader::MakeLinearGradient(
+          in_view_coordinates, colors, color_positions, 4,
+          SkShader::kClamp_TileMode));
+    } else {
+      flags.setColor(gradient_params_.color_to);
+    }
+
     flags.setStyle(cc::PaintFlags::kFill_Style);
     canvas->DrawRect(render_bounds, flags);
   } else {
@@ -371,7 +378,7 @@
 }
 
 void ScrollableUsersListView::OnHover(bool has_hover) {
-  scroll_bar_->SetThumbVisible(has_hover);
+  vertical_scroll_bar_->SetThumbVisible(has_hover);
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/scrollable_users_list_view.h b/ash/login/ui/scrollable_users_list_view.h
index ce3e79b6..587f4576 100644
--- a/ash/login/ui/scrollable_users_list_view.h
+++ b/ash/login/ui/scrollable_users_list_view.h
@@ -101,7 +101,7 @@
   views::BoxLayout* user_view_host_layout_ = nullptr;
 
   // Owned by ScrollView.
-  ScrollBar* scroll_bar_ = nullptr;
+  ScrollBar* vertical_scroll_bar_ = nullptr;
 
   std::vector<LoginUserView*> user_views_;
 
diff --git a/ash/pointer_watcher_adapter_classic.cc b/ash/pointer_watcher_adapter.cc
similarity index 85%
rename from ash/pointer_watcher_adapter_classic.cc
rename to ash/pointer_watcher_adapter.cc
index 4dabdd9e..96bbea0 100644
--- a/ash/pointer_watcher_adapter_classic.cc
+++ b/ash/pointer_watcher_adapter.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 "ash/pointer_watcher_adapter_classic.h"
+#include "ash/pointer_watcher_adapter.h"
 
 #include "ash/shell.h"
 #include "ui/aura/client/screen_position_client.h"
@@ -16,15 +16,15 @@
 
 namespace ash {
 
-PointerWatcherAdapterClassic::PointerWatcherAdapterClassic() {
+PointerWatcherAdapter::PointerWatcherAdapter() {
   Shell::Get()->AddPreTargetHandler(this);
 }
 
-PointerWatcherAdapterClassic::~PointerWatcherAdapterClassic() {
+PointerWatcherAdapter::~PointerWatcherAdapter() {
   Shell::Get()->RemovePreTargetHandler(this);
 }
 
-void PointerWatcherAdapterClassic::AddPointerWatcher(
+void PointerWatcherAdapter::AddPointerWatcher(
     views::PointerWatcher* watcher,
     views::PointerWatcherEventTypes events) {
   // We only allow a watcher to be added once. That is, we don't consider
@@ -40,14 +40,14 @@
     non_move_watchers_.AddObserver(watcher);
 }
 
-void PointerWatcherAdapterClassic::RemovePointerWatcher(
+void PointerWatcherAdapter::RemovePointerWatcher(
     views::PointerWatcher* watcher) {
   non_move_watchers_.RemoveObserver(watcher);
   move_watchers_.RemoveObserver(watcher);
   drag_watchers_.RemoveObserver(watcher);
 }
 
-void PointerWatcherAdapterClassic::OnMouseEvent(ui::MouseEvent* event) {
+void PointerWatcherAdapter::OnMouseEvent(ui::MouseEvent* event) {
   if (event->type() != ui::ET_MOUSE_PRESSED &&
       event->type() != ui::ET_MOUSE_RELEASED &&
       event->type() != ui::ET_MOUSE_MOVED &&
@@ -60,7 +60,7 @@
   NotifyWatchers(ui::PointerEvent(*event), *event);
 }
 
-void PointerWatcherAdapterClassic::OnTouchEvent(ui::TouchEvent* event) {
+void PointerWatcherAdapter::OnTouchEvent(ui::TouchEvent* event) {
   if (event->type() != ui::ET_TOUCH_PRESSED &&
       event->type() != ui::ET_TOUCH_RELEASED &&
       event->type() != ui::ET_TOUCH_MOVED)
@@ -70,7 +70,7 @@
   NotifyWatchers(ui::PointerEvent(*event), *event);
 }
 
-gfx::Point PointerWatcherAdapterClassic::GetLocationInScreen(
+gfx::Point PointerWatcherAdapter::GetLocationInScreen(
     const ui::LocatedEvent& event) const {
   gfx::Point location_in_screen;
   if (event.type() == ui::ET_MOUSE_CAPTURE_CHANGED) {
@@ -84,7 +84,7 @@
   return location_in_screen;
 }
 
-void PointerWatcherAdapterClassic::NotifyWatchers(
+void PointerWatcherAdapter::NotifyWatchers(
     const ui::PointerEvent& event,
     const ui::LocatedEvent& original_event) {
   const gfx::Point screen_location(GetLocationInScreen(original_event));
diff --git a/ash/pointer_watcher_adapter_classic.h b/ash/pointer_watcher_adapter.h
similarity index 81%
rename from ash/pointer_watcher_adapter_classic.h
rename to ash/pointer_watcher_adapter.h
index a4c2f4a..43c202d 100644
--- a/ash/pointer_watcher_adapter_classic.h
+++ b/ash/pointer_watcher_adapter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_POINTER_WATCHER_ADAPTER_CLASSIC_H_
-#define ASH_POINTER_WATCHER_ADAPTER_CLASSIC_H_
+#ifndef ASH_POINTER_WATCHER_ADAPTER_H_
+#define ASH_POINTER_WATCHER_ADAPTER_H_
 
 #include "ash/ash_export.h"
 #include "base/macros.h"
@@ -27,12 +27,12 @@
 
 namespace ash {
 
-// Support for PointerWatchers in non-mus ash, implemented with a pre-target
+// Support for PointerWatchers in ash, implemented with a pre-target
 // EventHandler on the Shell.
-class ASH_EXPORT PointerWatcherAdapterClassic : public ui::EventHandler {
+class ASH_EXPORT PointerWatcherAdapter : public ui::EventHandler {
  public:
-  PointerWatcherAdapterClassic();
-  ~PointerWatcherAdapterClassic() override;
+  PointerWatcherAdapter();
+  ~PointerWatcherAdapter() override;
 
   // See Shell::AddPointerWatcher() for details.
   void AddPointerWatcher(views::PointerWatcher* watcher,
@@ -62,9 +62,9 @@
   base::ObserverList<views::PointerWatcher, true> move_watchers_;
   base::ObserverList<views::PointerWatcher, true> drag_watchers_;
 
-  DISALLOW_COPY_AND_ASSIGN(PointerWatcherAdapterClassic);
+  DISALLOW_COPY_AND_ASSIGN(PointerWatcherAdapter);
 };
 
 }  // namespace ash
 
-#endif  // ASH_POINTER_WATCHER_ADAPTER_CLASSIC_H_
+#endif  // ASH_POINTER_WATCHER_ADAPTER_H_
diff --git a/ash/pointer_watcher_adapter_classic_unittest.cc b/ash/pointer_watcher_adapter_unittest.cc
similarity index 94%
rename from ash/pointer_watcher_adapter_classic_unittest.cc
rename to ash/pointer_watcher_adapter_unittest.cc
index 82930e3..e622f2e 100644
--- a/ash/pointer_watcher_adapter_classic_unittest.cc
+++ b/ash/pointer_watcher_adapter_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/public/cpp/config.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ui/events/base_event_utils.h"
@@ -13,7 +12,7 @@
 
 namespace ash {
 
-using PointerWatcherAdapterClassicTest = AshTestBase;
+using PointerWatcherAdapterTest = AshTestBase;
 
 enum TestPointerCaptureEvents {
   NONE = 0x01,
@@ -149,11 +148,7 @@
   DISALLOW_COPY_AND_ASSIGN(TestHelper);
 };
 
-TEST_F(PointerWatcherAdapterClassicTest, MouseEvents) {
-  // Not relevant for mash.
-  if (Shell::GetAshConfig() == Config::MASH_DEPRECATED)
-    return;
-
+TEST_F(PointerWatcherAdapterTest, MouseEvents) {
   TestHelper helper;
 
   // Move: only the move and drag PointerWatcher should get the event.
@@ -195,11 +190,7 @@
   helper.ExpectCallCount(CAPTURE, CAPTURE, CAPTURE);
 }
 
-TEST_F(PointerWatcherAdapterClassicTest, TouchEvents) {
-  // Not relevant for mash.
-  if (Shell::GetAshConfig() == Config::MASH_DEPRECATED)
-    return;
-
+TEST_F(PointerWatcherAdapterTest, TouchEvents) {
   TestHelper helper;
 
   // Press: all.
diff --git a/ash/public/cpp/accelerators.cc b/ash/public/cpp/accelerators.cc
index 447e1a7..85abf44 100644
--- a/ash/public/cpp/accelerators.cc
+++ b/ash/public/cpp/accelerators.cc
@@ -99,7 +99,12 @@
     {true, ui::VKEY_BROWSER_REFRESH,
      ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, ROTATE_WINDOW},
     {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, RESTORE_TAB},
+    // These correspond to the "Print Screen" key, which changed from VKEY_PRINT
+    // to VKEY_SNAPSHOT in the XKB code used by Chrome OS in M66. The X11 code
+    // used when running an OS_CHROMEOS build on a Linux workstation still uses
+    // VKEY_PRINT: https://crbug.com/872094
     {true, ui::VKEY_PRINT, ui::EF_NONE, TAKE_SCREENSHOT},
+    {true, ui::VKEY_SNAPSHOT, ui::EF_NONE, TAKE_SCREENSHOT},
     // On Chrome OS, Search key is mapped to LWIN. The Search key binding should
     // act on release instead of press when using Search as a modifier key for
     // extended keyboard shortcuts.
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 42f83a2..e6e85c0 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -212,10 +212,6 @@
   // panel height. The Docked Magnifier appears above the ChromeVox panel.
   void SetDockedMagnifierHeight(int height);
 
-  gfx::Rect keyboard_occluded_bounds() const {
-    return keyboard_occluded_bounds_;
-  }
-
  private:
   class UpdateShelfObserver;
   friend class PanelLayoutManagerTest;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 22d8571..6218d257 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -967,15 +967,13 @@
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
 
   // Blurred wallpaper.
-  ash::Shell::Get()->wallpaper_controller()->UpdateWallpaperBlur(
-      true /*locking*/);
+  ash::Shell::Get()->wallpaper_controller()->UpdateWallpaperBlur(/*blur=*/true);
   EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType());
 
   // Non-blurred wallpaper.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       ash::switches::kAshDisableLoginDimAndBlur);
-  ash::Shell::Get()->wallpaper_controller()->UpdateWallpaperBlur(
-      true /*locking*/);
+  ash::Shell::Get()->wallpaper_controller()->UpdateWallpaperBlur(/*blur=*/true);
   EXPECT_EQ(SHELF_BACKGROUND_LOGIN_NONBLURRED_WALLPAPER,
             GetShelfWidget()->GetBackgroundType());
 }
diff --git a/ash/shell.cc b/ash/shell.cc
index 4ef93d3..b2b099c 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -69,7 +69,7 @@
 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
 #include "ash/new_window_controller.h"
 #include "ash/note_taking_controller.h"
-#include "ash/pointer_watcher_adapter_classic.h"
+#include "ash/pointer_watcher_adapter.h"
 #include "ash/policy/policy_recommendation_restorer.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
@@ -1200,7 +1200,7 @@
 
   // Must occur after Shell has installed its early pre-target handlers (for
   // example, WindowModalityController).
-  pointer_watcher_adapter_ = std::make_unique<PointerWatcherAdapterClassic>();
+  pointer_watcher_adapter_ = std::make_unique<PointerWatcherAdapter>();
 
   resize_shadow_controller_.reset(new ResizeShadowController());
   shadow_controller_.reset(new ::wm::ShadowController(
diff --git a/ash/shell.h b/ash/shell.h
index eb56c0f..9231682 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -153,7 +153,7 @@
 class PartialMagnificationController;
 class PeripheralBatteryNotifier;
 class PersistentWindowController;
-class PointerWatcherAdapterClassic;
+class PointerWatcherAdapter;
 class PolicyRecommendationRestorer;
 class PowerButtonController;
 class PowerEventObserver;
@@ -755,7 +755,7 @@
   std::unique_ptr<MultiDeviceNotificationPresenter>
       multidevice_notification_presenter_;
   std::unique_ptr<NewWindowController> new_window_controller_;
-  std::unique_ptr<PointerWatcherAdapterClassic> pointer_watcher_adapter_;
+  std::unique_ptr<PointerWatcherAdapter> pointer_watcher_adapter_;
   std::unique_ptr<ResizeShadowController> resize_shadow_controller_;
   std::unique_ptr<SessionController> session_controller_;
   std::unique_ptr<NightLightController> night_light_controller_;
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 91169b8b..33a93ec1 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -476,14 +476,8 @@
   gfx::Insets anchor_insets = GetBubbleAnchor()->GetInsets();
   gfx::Insets tray_bg_insets = GetInsets();
   if (GetAnchorAlignment() == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
-    // TODO(blakeo): There are minor variances in padding depending on if the
-    // keyboard is in anchored accessibility mode or in regular mode.
-    const gfx::Rect keyboard_occluding_bounds =
-        shelf_->shelf_layout_manager()->keyboard_occluded_bounds();
-    int keyboard_offset = keyboard_occluding_bounds.height();
-    return gfx::Insets(-tray_bg_insets.top() - keyboard_offset,
-                       anchor_insets.left(), -tray_bg_insets.bottom(),
-                       anchor_insets.right());
+    return gfx::Insets(-tray_bg_insets.top(), anchor_insets.left(),
+                       -tray_bg_insets.bottom(), anchor_insets.right());
   } else {
     return gfx::Insets(anchor_insets.top(), -tray_bg_insets.left(),
                        anchor_insets.bottom(), -tray_bg_insets.right());
diff --git a/ash/system/tray/tray_container.cc b/ash/system/tray/tray_container.cc
index f11417b0..18cdf0f 100644
--- a/ash/system/tray/tray_container.cc
+++ b/ash/system/tray/tray_container.cc
@@ -9,6 +9,7 @@
 #include "ash/shelf/shelf.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/keyboard/keyboard_controller.h"
 #include "ui/views/border.h"
 #include "ui/views/layout/box_layout.h"
 
@@ -46,6 +47,18 @@
     PreferredSizeChanged();
 }
 
+gfx::Rect TrayContainer::GetAnchorBoundsInScreen() const {
+  if (shelf_->IsHorizontalAlignment()) {
+    // When the virtual keyboard is up, any anchored widgets should anchor to
+    // the virtual keyboard instead because it will cover the shelf.
+    const gfx::Rect occluded_bounds =
+        keyboard::KeyboardController::Get()->GetWorkspaceOccludedBounds();
+    if (!occluded_bounds.IsEmpty())
+      return occluded_bounds;
+  }
+  return GetBoundsInScreen();
+}
+
 void TrayContainer::UpdateLayout() {
   const bool is_horizontal = shelf_->IsHorizontalAlignment();
 
diff --git a/ash/system/tray/tray_container.h b/ash/system/tray/tray_container.h
index 1ad0dc3..e07b593 100644
--- a/ash/system/tray/tray_container.h
+++ b/ash/system/tray/tray_container.h
@@ -28,6 +28,7 @@
   void ChildVisibilityChanged(View* child) override;
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
+  gfx::Rect GetAnchorBoundsInScreen() const override;
 
  private:
   void UpdateLayout();
diff --git a/ash/system/unified/unified_message_center_view.cc b/ash/system/unified/unified_message_center_view.cc
index 969b2d1c..db5b1e71 100644
--- a/ash/system/unified/unified_message_center_view.cc
+++ b/ash/system/unified/unified_message_center_view.cc
@@ -17,6 +17,7 @@
 #include "ui/message_center/views/notification_control_buttons_view.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget.h"
 
 using message_center::MessageCenter;
 using message_center::MessageView;
@@ -232,6 +233,8 @@
 
 void UnifiedMessageCenterView::Update() {
   SetVisible(message_list_view_->GetNotificationCount() > 0);
+  if (GetWidget() && !GetWidget()->IsClosed())
+    tray_controller_->OnMessageCenterVisibilityUpdated();
 
   size_t notification_count = message_list_view_->GetNotificationCount();
   // TODO(tetsui): This is O(n^2).
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index 397e0f6..a2a78b2 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/unified_slider_bubble_controller.h"
 
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/audio/unified_volume_slider_controller.h"
@@ -12,6 +13,7 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/unified_system_tray.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 
 using chromeos::CrasAudioHandler;
 
@@ -28,6 +30,12 @@
   return false;
 }
 
+void ConfigureSliderViewStyle(views::View* slider_view) {
+  slider_view->SetBackground(UnifiedSystemTrayView::CreateBackground());
+  slider_view->SetBorder(
+      views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
+}
+
 }  // namespace
 
 UnifiedSliderBubbleController::UnifiedSliderBubbleController(
@@ -124,6 +132,7 @@
 
       UnifiedSliderView* slider_view =
           static_cast<UnifiedSliderView*>(slider_controller_->CreateView());
+      ConfigureSliderViewStyle(slider_view);
       bubble_view_->AddChildView(slider_view);
       bubble_view_->Layout();
     }
@@ -148,14 +157,16 @@
   init_params.parent_window = tray_->GetBubbleWindowContainer();
   init_params.anchor_view =
       tray_->shelf()->GetSystemTrayAnchor()->GetBubbleAnchor();
+  init_params.corner_radius = kUnifiedTrayCornerRadius;
+  init_params.has_shadow = false;
 
   bubble_view_ = new views::TrayBubbleView(init_params);
   UnifiedSliderView* slider_view =
       static_cast<UnifiedSliderView*>(slider_controller_->CreateView());
+  ConfigureSliderViewStyle(slider_view);
   bubble_view_->AddChildView(slider_view);
-  bubble_view_->SetBorder(
-      views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
-  bubble_view_->set_color(kUnifiedMenuBackgroundColor);
+  bubble_view_->set_color(SK_ColorTRANSPARENT);
+  bubble_view_->layer()->SetFillsBoundsOpaquely(false);
   bubble_view_->set_anchor_view_insets(
       tray_->shelf()->GetSystemTrayAnchor()->GetBubbleAnchorInsets());
 
@@ -164,6 +175,11 @@
   TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
   bubble_view_->InitializeAndShowBubble();
 
+  if (app_list::features::IsBackgroundBlurEnabled()) {
+    bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+        kUnifiedMenuBackgroundBlur);
+  }
+
   // Notify value change accessibility event because the popup is triggered by
   // changing value using an accessor key like VolUp.
   slider_view->slider()->NotifyAccessibilityEvent(
diff --git a/ash/system/unified/unified_slider_view.cc b/ash/system/unified/unified_slider_view.cc
index a8b242e..5b5ff822 100644
--- a/ash/system/unified/unified_slider_view.cc
+++ b/ash/system/unified/unified_slider_view.cc
@@ -12,6 +12,7 @@
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/border.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget.h"
 
 namespace ash {
 
@@ -111,6 +112,14 @@
 }
 
 void UnifiedSliderView::SetSliderValue(float value, bool by_user) {
+  // SetValue() calls |listener|, so we should ignore the call when the widget
+  // is closed, because controllers are already deleted.
+  // It should allow the case GetWidget() returning null, so that initial
+  // position can be properly set by controllers before the view is attached to
+  // a widget.
+  if (GetWidget() && GetWidget()->IsClosed())
+    return;
+
   slider_->SetValue(value);
   if (by_user)
     slider_->set_enable_accessibility_events(true);
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index f95455e2..725292be 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -171,6 +171,11 @@
       message_center::MessageCenter::RemoveType::NON_PINNED);
 }
 
+void UnifiedSystemTrayController::OnMessageCenterVisibilityUpdated() {
+  if (bubble_)
+    bubble_->UpdateTransform();
+}
+
 void UnifiedSystemTrayController::BeginDrag(const gfx::Point& location) {
   drag_init_point_ = location;
   was_expanded_ = IsExpanded();
diff --git a/ash/system/unified/unified_system_tray_controller.h b/ash/system/unified/unified_system_tray_controller.h
index 69929aec..7f24e96 100644
--- a/ash/system/unified/unified_system_tray_controller.h
+++ b/ash/system/unified/unified_system_tray_controller.h
@@ -62,6 +62,9 @@
   // Called when notification removing animation is finished. Called from the
   // view.
   void OnClearAllAnimationEnded();
+  // Called when message center visibility is changed. Called from the
+  // view.
+  void OnMessageCenterVisibilityUpdated();
 
   // Handle finger dragging and expand/collapse the view. Called from view.
   void BeginDrag(const gfx::Point& location);
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index 544e3fd..1f74ed5 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -60,15 +60,6 @@
   return view;
 }
 
-std::unique_ptr<views::Background> CreateUnifiedBackground() {
-  return views::CreateBackgroundFromPainter(
-      views::Painter::CreateSolidRoundRectPainter(
-          app_list::features::IsBackgroundBlurEnabled()
-              ? kUnifiedMenuBackgroundColorWithBlur
-              : kUnifiedMenuBackgroundColor,
-          kUnifiedTrayCornerRadius));
-}
-
 // Border applied to SystemTrayContainer and DetailedViewContainer to iminate
 // notification list scrolling under SystemTray part of UnifiedSystemTray.
 // The border paints mock notification frame behind the top corners based on
@@ -120,7 +111,7 @@
   SystemTrayContainer() {
     SetLayoutManager(
         std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
-    SetBackground(CreateUnifiedBackground());
+    SetBackground(UnifiedSystemTrayView::CreateBackground());
     SetBorder(std::make_unique<TopCornerBorder>());
   }
 
@@ -138,7 +129,7 @@
 class DetailedViewContainer : public views::View {
  public:
   DetailedViewContainer() {
-    SetBackground(CreateUnifiedBackground());
+    SetBackground(UnifiedSystemTrayView::CreateBackground());
     SetBorder(std::make_unique<TopCornerBorder>());
   }
 
@@ -267,7 +258,7 @@
   auto* layout = SetLayoutManager(
       std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
 
-  SetBackground(CreateUnifiedBackground());
+  SetBackground(CreateBackground());
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
 
@@ -410,6 +401,16 @@
   SchedulePaint();
 }
 
+// static
+std::unique_ptr<views::Background> UnifiedSystemTrayView::CreateBackground() {
+  return views::CreateBackgroundFromPainter(
+      views::Painter::CreateSolidRoundRectPainter(
+          app_list::features::IsBackgroundBlurEnabled()
+              ? kUnifiedMenuBackgroundColorWithBlur
+              : kUnifiedMenuBackgroundColor,
+          kUnifiedTrayCornerRadius));
+}
+
 void UnifiedSystemTrayView::OnGestureEvent(ui::GestureEvent* event) {
   gfx::Point screen_location = event->location();
   ConvertPointToScreen(this, &screen_location);
diff --git a/ash/system/unified/unified_system_tray_view.h b/ash/system/unified/unified_system_tray_view.h
index b089a2a..250e859 100644
--- a/ash/system/unified/unified_system_tray_view.h
+++ b/ash/system/unified/unified_system_tray_view.h
@@ -99,6 +99,10 @@
   // scrolling under SystemTray. |height_below_scroll| should not be negative.
   void SetNotificationHeightBelowScroll(int height_below_scroll);
 
+  // Create background of UnifiedSystemTray that is semi-transparent and has
+  // rounded corners.
+  static std::unique_ptr<views::Background> CreateBackground();
+
   // views::View:
   void OnGestureEvent(ui::GestureEvent* event) override;
   void ChildPreferredSizeChanged(views::View* child) override;
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index c69da28..ba2eccb 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -708,8 +708,8 @@
          info.type == POLICY;
 }
 
-void WallpaperController::UpdateWallpaperBlur(bool locking) {
-  bool needs_blur = locking && IsBlurEnabled();
+void WallpaperController::UpdateWallpaperBlur(bool blur) {
+  bool needs_blur = blur && IsBlurAllowed();
   if (needs_blur == is_wallpaper_blurred_)
     return;
 
@@ -732,7 +732,7 @@
              switches::kAshDisableLoginDimAndBlur);
 }
 
-bool WallpaperController::IsBlurEnabled() const {
+bool WallpaperController::IsBlurAllowed() const {
   return !IsDevicePolicyWallpaper() &&
          !base::CommandLine::ForCurrentProcess()->HasSwitch(
              switches::kAshDisableLoginDimAndBlur);
@@ -1441,7 +1441,7 @@
       Shell::Get()->session_controller()->IsUserSessionBlocked();
   bool in_overview = Shell::Get()->window_selector_controller()->IsSelecting();
   bool is_wallpaper_blurred =
-      (session_blocked || in_overview) && IsBlurEnabled();
+      (session_blocked || in_overview) && IsBlurAllowed();
 
   if (is_wallpaper_blurred_ != is_wallpaper_blurred) {
     is_wallpaper_blurred_ = is_wallpaper_blurred;
diff --git a/ash/wallpaper/wallpaper_controller.h b/ash/wallpaper/wallpaper_controller.h
index 04e9f02..9ae7714b 100644
--- a/ash/wallpaper/wallpaper_controller.h
+++ b/ash/wallpaper/wallpaper_controller.h
@@ -159,17 +159,17 @@
   // including device policy).
   bool IsPolicyControlled(const AccountId& account_id, bool is_ephemeral) const;
 
-  // Prepares wallpaper to lock screen transition. Will apply blur if |locking|
-  // is true and blur is enabled by the controller, otherwise any existing blur
-  // will be removed.
-  void UpdateWallpaperBlur(bool locking);
+  // Update the blurred state of the current wallpaper. Applies blur if |blur|
+  // is true and blur is allowed by the controller, otherwise any existing blur
+  // is removed.
+  void UpdateWallpaperBlur(bool blur);
 
   // Wallpaper should be dimmed for login, lock, OOBE and add user screens.
   bool ShouldApplyDimming() const;
 
-  // Returns whether blur is enabled for login, lock, OOBE and add user screens.
-  // See crbug.com/775591.
-  bool IsBlurEnabled() const;
+  // Returns whether the current wallpaper is allowed to be blurred. See
+  // https://crbug.com/775591.
+  bool IsBlurAllowed() const;
 
   // Returns whether the current wallpaper is blurred.
   bool IsWallpaperBlurred() const { return is_wallpaper_blurred_; }
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index b6451ce..f1081cd9 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -1803,7 +1803,7 @@
 }
 
 TEST_F(WallpaperControllerTest, WallpaperBlur) {
-  ASSERT_TRUE(controller_->IsBlurEnabled());
+  ASSERT_TRUE(controller_->IsBlurAllowed());
   ASSERT_FALSE(controller_->IsWallpaperBlurred());
 
   TestWallpaperControllerObserver observer;
@@ -1843,7 +1843,7 @@
 }
 
 TEST_F(WallpaperControllerTest, WallpaperBlurDuringLockScreenTransition) {
-  ASSERT_TRUE(controller_->IsBlurEnabled());
+  ASSERT_TRUE(controller_->IsBlurAllowed());
   ASSERT_FALSE(controller_->IsWallpaperBlurred());
 
   TestWallpaperControllerObserver observer;
@@ -1876,7 +1876,7 @@
   EXPECT_EQ(1, GetWallpaperCount());
   EXPECT_TRUE(IsDevicePolicyWallpaper());
   // Verify the device policy wallpaper shouldn't be blurred.
-  ASSERT_FALSE(controller_->IsBlurEnabled());
+  ASSERT_FALSE(controller_->IsBlurAllowed());
   ASSERT_FALSE(controller_->IsWallpaperBlurred());
 
   // Verify the device policy wallpaper is replaced when session state is no
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 6921bb2..b9f04db 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -73,9 +73,9 @@
   return false;
 }
 
-bool IsBlurEnabled() {
+bool IsBlurAllowed() {
   return !g_disable_wallpaper_blur_for_tests &&
-         Shell::Get()->wallpaper_controller()->IsBlurEnabled();
+         Shell::Get()->wallpaper_controller()->IsBlurAllowed();
 }
 
 }  // namespace
@@ -260,7 +260,7 @@
     window_selector_.reset(new WindowSelector(this));
     Shell::Get()->NotifyOverviewModeStarting();
     window_selector_->Init(windows, hide_windows);
-    if (IsBlurEnabled())
+    if (IsBlurAllowed())
       overview_blur_controller_->Blur();
     OnSelectionStarted();
   }
@@ -401,7 +401,7 @@
   if (is_shutting_down_)
     return;
 
-  if (IsBlurEnabled())
+  if (IsBlurAllowed())
     overview_blur_controller_->Unblur();
   is_shutting_down_ = true;
   Shell::Get()->NotifyOverviewModeEnding();
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index dea2fc5..16caca96 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -2529,4 +2529,44 @@
   EXPECT_TRUE(shelf_layout_manager->IsVisible());
 }
 
+// Tests that the app drag will be reverted if the screen is being rotated.
+TEST_F(SplitViewAppDraggingTest, DisplayConfigurationChangeTest) {
+  UpdateDisplay("800x600");
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  display::DisplayManager* display_manager = Shell::Get()->display_manager();
+  display::test::ScopedSetInternalDisplayId set_internal(display_manager,
+                                                         display_id);
+  ScreenOrientationControllerTestApi test_api(
+      Shell::Get()->screen_orientation_controller());
+  // Set the screen orientation to LANDSCAPE_PRIMARY.
+  test_api.SetDisplayRotation(display::Display::ROTATE_0,
+                              display::Display::RotationSource::ACTIVE);
+  EXPECT_EQ(test_api.GetCurrentOrientation(),
+            OrientationLockType::kLandscapePrimary);
+
+  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
+  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  gfx::Rect display_bounds =
+      split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window.get());
+
+  // Start to drag the window long enough to snap.
+  const float long_scroll_delta = display_bounds.height() / 4 + 5;
+  base::TimeTicks timestamp = base::TimeTicks::Now();
+  SendScrollStartAndUpdate(gfx::Point(0, 0), long_scroll_delta, timestamp,
+                           window.get());
+  WindowSelectorController* window_selector_controller =
+      Shell::Get()->window_selector_controller();
+  EXPECT_TRUE(window_selector_controller->IsSelecting());
+  EXPECT_TRUE(wm::GetWindowState(window.get())->is_dragged());
+
+  // Rotate the screen during drag.
+  test_api.SetDisplayRotation(display::Display::ROTATE_270,
+                              display::Display::RotationSource::ACTIVE);
+  EXPECT_EQ(test_api.GetCurrentOrientation(),
+            OrientationLockType::kPortraitPrimary);
+  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  EXPECT_FALSE(window_selector_controller->IsSelecting());
+  EXPECT_FALSE(wm::GetWindowState(window.get())->is_dragged());
+}
+
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
index 0d2c414..167f56b 100644
--- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
@@ -53,13 +53,17 @@
 }  // namespace
 
 TabletModeAppWindowDragController::TabletModeAppWindowDragController()
-    : drag_delegate_(std::make_unique<TabletModeAppWindowDragDelegate>()) {}
+    : drag_delegate_(std::make_unique<TabletModeAppWindowDragDelegate>()) {
+  display::Screen::GetScreen()->AddObserver(this);
+}
 
-TabletModeAppWindowDragController::~TabletModeAppWindowDragController() =
-    default;
+TabletModeAppWindowDragController::~TabletModeAppWindowDragController() {
+  display::Screen::GetScreen()->RemoveObserver(this);
+}
 
 bool TabletModeAppWindowDragController::DragWindowFromTop(
     ui::GestureEvent* event) {
+  previous_location_in_screen_ = GetEventLocationInScreen(event);
   if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN)
     return StartWindowDrag(event);
 
@@ -114,4 +118,21 @@
   drag_delegate_->EndWindowDrag(result, GetEventLocationInScreen(event));
 }
 
+void TabletModeAppWindowDragController::OnDisplayMetricsChanged(
+    const display::Display& display,
+    uint32_t metrics) {
+  if (!drag_delegate_->dragged_window() || !(metrics & DISPLAY_METRIC_ROTATION))
+    return;
+
+  display::Display current_display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(
+          drag_delegate_->dragged_window());
+  if (display.id() != current_display.id())
+    return;
+
+  drag_delegate_->EndWindowDrag(
+      wm::WmToplevelWindowEventHandler::DragResult::REVERT,
+      previous_location_in_screen_);
+}
+
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
index f745936..a0a13a2 100644
--- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
+++ b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
@@ -7,6 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/wm/wm_toplevel_window_event_handler.h"
+#include "ui/display/display_observer.h"
 
 namespace ui {
 class GestureEvent;
@@ -17,13 +18,14 @@
 
 // Handles app windows dragging in tablet mode. App windows can be dragged into
 // splitscreen through swiping from the top of the screen in tablet mode.
-class ASH_EXPORT TabletModeAppWindowDragController {
+class ASH_EXPORT TabletModeAppWindowDragController
+    : public display::DisplayObserver {
  public:
   // Threshold of the fling velocity to drop the window into overview.
   static constexpr float kFlingToOverviewThreshold = 100.0f;
 
   TabletModeAppWindowDragController();
-  ~TabletModeAppWindowDragController();
+  ~TabletModeAppWindowDragController() override;
 
   // Processes a gesture event and updates the transform of |dragged_window_|.
   // Returns true if the gesture has been handled and it should not be processed
@@ -38,7 +40,12 @@
   void EndWindowDrag(ui::GestureEvent* event,
                      wm::WmToplevelWindowEventHandler::DragResult result);
 
+  // display::DisplayObserver:
+  void OnDisplayMetricsChanged(const display::Display& display,
+                               uint32_t metrics) override;
+
   std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate_;
+  gfx::Point previous_location_in_screen_;
 
   DISALLOW_COPY_AND_ASSIGN(TabletModeAppWindowDragController);
 };
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 9a0e580..bb9ba9f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2423,6 +2423,7 @@
     "test/metrics/user_action_tester_unittest.cc",
     "test/mock_callback_unittest.cc",
     "test/scoped_feature_list_unittest.cc",
+    "test/scoped_mock_clock_override_unittest.cc",
     "test/scoped_mock_time_message_loop_task_runner_unittest.cc",
     "test/scoped_task_environment_unittest.cc",
     "test/test_mock_time_task_runner_unittest.cc",
diff --git a/base/android/jni_generator/jni_exception_list.gni b/base/android/jni_generator/jni_exception_list.gni
index 11c7f6a..31d027ca 100644
--- a/base/android/jni_generator/jni_exception_list.gni
+++ b/base/android/jni_generator/jni_exception_list.gni
@@ -9,5 +9,5 @@
 
 # Exclude it from JNI registration if VR is not enabled.
 if (!enable_vr) {
-  jni_exception_files += [ "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java" ]
+  jni_exception_files += [ "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java" ]
 }
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 62ee862..12812a5 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -294,8 +294,6 @@
     content = h2.Generate()
     for k in jni_registration_generator.MERGEABLE_KEYS:
       content[k] = content.get(k, '')
-    content['HEADER_GUARD'] = 'HEADER_GUARD'
-    content['NAMESPACE'] = 'test'
 
     self.assertGoldenTextEquals(
         jni_registration_generator.CreateFromDict(content),
@@ -385,8 +383,6 @@
     content = h2.Generate()
     for k in jni_registration_generator.MERGEABLE_KEYS:
       content[k] = content.get(k, '')
-    content['HEADER_GUARD'] = 'HEADER_GUARD'
-    content['NAMESPACE'] = 'test'
 
     self.assertGoldenTextEquals(
         jni_registration_generator.CreateFromDict(content),
diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py
index 44f97df..d4fb39a 100755
--- a/base/android/jni_generator/jni_registration_generator.py
+++ b/base/android/jni_generator/jni_registration_generator.py
@@ -12,7 +12,6 @@
 import argparse
 import jni_generator
 import multiprocessing
-import os
 import string
 import sys
 from util import build_utils
@@ -55,10 +54,6 @@
   for key in MERGEABLE_KEYS:
     combined_dict[key] = ''.join(d.get(key, '') for d in results)
 
-  combined_dict['HEADER_GUARD'] = \
-      os.path.splitext(output_file)[0].replace('/', '_').upper() + '_'
-  combined_dict['NAMESPACE'] = args.namespace
-
   header_content = CreateFromDict(combined_dict)
   if output_file:
     jni_generator.WriteOutput(output_file, header_content)
@@ -96,8 +91,8 @@
 //     base/android/jni_generator/jni_registration_generator.py
 // Please do not change its content.
 
-#ifndef ${HEADER_GUARD}
-#define ${HEADER_GUARD}
+#ifndef HEADER_GUARD
+#define HEADER_GUARD
 
 #include <jni.h>
 
@@ -118,8 +113,6 @@
 ${JNI_NATIVE_METHOD}
 // Step 4: Main dex and non-main dex registration functions.
 
-namespace ${NAMESPACE} {
-
 bool RegisterMainDexNatives(JNIEnv* env) {
 ${REGISTER_MAIN_DEX_NATIVES}
   return true;
@@ -130,9 +123,7 @@
   return true;
 }
 
-}  // namespace ${NAMESPACE}
-
-#endif  // ${HEADER_GUARD}
+#endif  // HEADER_GUARD
 """)
   if len(registration_dict['FORWARD_DECLARATIONS']) == 0:
     return ''
@@ -324,13 +315,8 @@
   arg_parser.add_argument('--output',
                           help='The output file path.')
   arg_parser.add_argument('--no_register_java',
-                          default=[],
                           help='A list of Java files which should be ignored '
                           'by the parser.')
-  arg_parser.add_argument('--namespace',
-                          default='',
-                          help='Namespace to wrap the registration functions '
-                          'into.')
   args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:]))
   args.sources_files = build_utils.ParseGnList(args.sources_files)
 
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuterRegistrations.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuterRegistrations.golden
index 1109d142..44842c3 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuterRegistrations.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuterRegistrations.golden
@@ -94,8 +94,6 @@
 
 // Step 4: Main dex and non-main dex registration functions.
 
-namespace test {
-
 bool RegisterMainDexNatives(JNIEnv* env) {
   if (!RegisterNative_org_chromium_TestJni(env))
     return false;
@@ -108,6 +106,4 @@
   return true;
 }
 
-}  // namespace test
-
 #endif  // HEADER_GUARD
diff --git a/base/android/jni_generator/testNativesRegistrations.golden b/base/android/jni_generator/testNativesRegistrations.golden
index b3b99745..8856e05f 100644
--- a/base/android/jni_generator/testNativesRegistrations.golden
+++ b/base/android/jni_generator/testNativesRegistrations.golden
@@ -160,8 +160,6 @@
 
 // Step 4: Main dex and non-main dex registration functions.
 
-namespace test {
-
 bool RegisterMainDexNatives(JNIEnv* env) {
   if (!RegisterNative_org_chromium_TestJni(env))
     return false;
@@ -174,6 +172,4 @@
   return true;
 }
 
-}  // namespace test
-
 #endif  // HEADER_GUARD
diff --git a/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc b/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
index 2afa048a..49f70289 100644
--- a/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
+++ b/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/task/sequence_manager/lazily_deallocated_deque.h"
 
-#include "base/time/time_override.h"
+#include "base/test/scoped_mock_clock_override.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace base {
@@ -162,13 +162,8 @@
   EXPECT_EQ(LazilyDeallocatedDeque<int>::kMinimumRingSize, d.capacity());
 }
 
-namespace {
-TimeTicks fake_now;
-}
-
 TEST_F(LazilyDeallocatedDequeTest, MaybeShrinkQueueRateLimiting) {
-  subtle::ScopedTimeClockOverrides time_overrides(
-      nullptr, []() { return fake_now; }, nullptr);
+  ScopedMockClockOverride clock;
   LazilyDeallocatedDeque<int> d;
 
   for (int i = 0; i < 1000; i++) {
@@ -211,8 +206,8 @@
   EXPECT_EQ(901u, d.capacity());
 
   // After time passes we re-sample max_size.
-  fake_now += TimeDelta::FromSeconds(
-      LazilyDeallocatedDeque<int>::kMinimumShrinkIntervalInSeconds);
+  clock.Advance(TimeDelta::FromSeconds(
+      LazilyDeallocatedDeque<int>::kMinimumShrinkIntervalInSeconds));
   d.MaybeShrinkQueue();
   EXPECT_EQ(800u, d.max_size());
   EXPECT_EQ(901u, d.capacity());
diff --git a/base/task/sequence_manager/sequence_manager.h b/base/task/sequence_manager/sequence_manager.h
index b198189..20e9a704 100644
--- a/base/task/sequence_manager/sequence_manager.h
+++ b/base/task/sequence_manager/sequence_manager.h
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/timer_slack.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/task/sequence_manager/task_time_observer.h"
@@ -113,6 +114,10 @@
   // logic at the cost of a potentially worse latency. 1 by default.
   virtual void SetWorkBatchSize(int work_batch_size) = 0;
 
+  // Requests desired timer precision from the OS.
+  // Has no effect on some platforms.
+  virtual void SetTimerSlack(TimerSlack timer_slack) = 0;
+
   // Enables crash keys that can be set in the scope of a task which help
   // to identify the culprit if upcoming work results in a crash.
   // Key names must be thread-specific to avoid races and corrupted crash dumps.
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
index 4b9ed06c..3de7d1b7 100644
--- a/base/task/sequence_manager/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -582,6 +582,11 @@
   controller_->SetWorkBatchSize(work_batch_size);
 }
 
+void SequenceManagerImpl::SetTimerSlack(TimerSlack timer_slack) {
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
+  controller_->SetTimerSlack(timer_slack);
+}
+
 void SequenceManagerImpl::AddTaskObserver(
     MessageLoop::TaskObserver* task_observer) {
   DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
index ea8c53d7..f5e54ce 100644
--- a/base/task/sequence_manager/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -114,6 +114,7 @@
   void SweepCanceledDelayedTasks() override;
   bool GetAndClearSystemIsQuiescentBit() override;
   void SetWorkBatchSize(int work_batch_size) override;
+  void SetTimerSlack(TimerSlack timer_slack) override;
   void EnableCrashKeys(const char* file_name_crash_key,
                        const char* function_name_crash_key) override;
   const MetricRecordingSettings& GetMetricRecordingSettings() const override;
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index 5f007b2..9ccac1eb 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_current.h"
+#include "base/message_loop/message_pump_default.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -177,7 +178,8 @@
     mock_clock_.Advance(TimeDelta::FromMilliseconds(1));
     start_time_ = mock_clock_.NowTicks();
     manager_ = SequenceManagerForTest::Create(
-        std::make_unique<ThreadControllerWithMessagePumpImpl>(&mock_clock_));
+        std::make_unique<ThreadControllerWithMessagePumpImpl>(
+            std::make_unique<MessagePumpDefault>(), &mock_clock_));
     // ThreadControllerWithMessagePumpImpl doesn't provide a default tas runner.
     scoped_refptr<TaskQueue> default_task_queue =
         manager_->CreateTaskQueue<TestTaskQueue>(TaskQueue::Spec("default"));
diff --git a/base/task/sequence_manager/sequence_manager_perftest.cc b/base/task/sequence_manager/sequence_manager_perftest.cc
index 4bcffa8..ddc4fd4 100644
--- a/base/task/sequence_manager/sequence_manager_perftest.cc
+++ b/base/task/sequence_manager/sequence_manager_perftest.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_default.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
@@ -101,6 +102,7 @@
   void CreateSequenceManagerWithMessagePump() {
     manager_ = SequenceManagerForTest::Create(
         std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
+            std::make_unique<MessagePumpDefault>(),
             DefaultTickClock::GetInstance()));
     // ThreadControllerWithMessagePumpImpl doesn't provide a default tas runner.
     scoped_refptr<TaskQueue> default_task_queue =
diff --git a/base/task/sequence_manager/thread_controller.h b/base/task/sequence_manager/thread_controller.h
index 0ba52d85..be31660 100644
--- a/base/task/sequence_manager/thread_controller.h
+++ b/base/task/sequence_manager/thread_controller.h
@@ -5,6 +5,7 @@
 #ifndef BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_H_
 #define BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_H_
 
+#include "base/message_loop/timer_slack.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/lazy_now.h"
@@ -62,6 +63,10 @@
   // Must be called before the first call to Schedule*Work().
   virtual void SetSequencedTaskSource(SequencedTaskSource*) = 0;
 
+  // Requests desired timer precision from the OS.
+  // Has no effect on some platforms.
+  virtual void SetTimerSlack(TimerSlack timer_slack) = 0;
+
   // TODO(altimin): Get rid of the methods below.
   // These methods exist due to current integration of SequenceManager
   // with MessageLoop.
diff --git a/base/task/sequence_manager/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc
index 228b34c..230e5a9 100644
--- a/base/task/sequence_manager/thread_controller_impl.cc
+++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -62,6 +62,12 @@
   sequence_ = sequence;
 }
 
+void ThreadControllerImpl::SetTimerSlack(TimerSlack timer_slack) {
+  if (!message_loop_)
+    return;
+  message_loop_->SetTimerSlack(timer_slack);
+}
+
 void ThreadControllerImpl::ScheduleWork() {
   DCHECK(sequence_);
   AutoLock lock(any_sequence_lock_);
diff --git a/base/task/sequence_manager/thread_controller_impl.h b/base/task/sequence_manager/thread_controller_impl.h
index 609c85c2..efa771a3 100644
--- a/base/task/sequence_manager/thread_controller_impl.h
+++ b/base/task/sequence_manager/thread_controller_impl.h
@@ -42,6 +42,7 @@
   void ScheduleWork() override;
   void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override;
   void SetSequencedTaskSource(SequencedTaskSource* sequence) override;
+  void SetTimerSlack(TimerSlack timer_slack) override;
   bool RunsTasksInCurrentSequence() override;
   const TickClock* GetClock() override;
   void SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner>) override;
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
index 3dad1c5..9483a8d 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -5,7 +5,6 @@
 #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
 
 #include "base/auto_reset.h"
-#include "base/message_loop/message_pump_default.h"
 #include "base/time/tick_clock.h"
 #include "base/trace_event/trace_event.h"
 
@@ -14,16 +13,22 @@
 namespace internal {
 
 ThreadControllerWithMessagePumpImpl::ThreadControllerWithMessagePumpImpl(
+    std::unique_ptr<MessagePump> message_pump,
     const TickClock* time_source)
     : associated_thread_(AssociatedThreadId::CreateUnbound()),
-      pump_(new MessagePumpDefault()),
+      pump_(std::move(message_pump)),
       time_source_(time_source) {
+  scoped_set_sequence_local_storage_map_for_current_thread_ = std::make_unique<
+      base::internal::ScopedSetSequenceLocalStorageMapForCurrentThread>(
+      &sequence_local_storage_map_);
   RunLoop::RegisterDelegateForCurrentThread(this);
 }
 
 ThreadControllerWithMessagePumpImpl::~ThreadControllerWithMessagePumpImpl() {
   // Destructors of RunLoop::Delegate and ThreadTaskRunnerHandle
   // will do all the clean-up.
+  // ScopedSetSequenceLocalStorageMapForCurrentThread destructor will
+  // de-register the current thread as a sequence.
 }
 
 ThreadControllerWithMessagePumpImpl::MainThreadOnly::MainThreadOnly() = default;
@@ -44,34 +49,28 @@
   main_thread_only().batch_size = work_batch_size;
 }
 
+void ThreadControllerWithMessagePumpImpl::SetTimerSlack(
+    TimerSlack timer_slack) {
+  pump_->SetTimerSlack(timer_slack);
+}
+
 void ThreadControllerWithMessagePumpImpl::WillQueueTask(
     PendingTask* pending_task) {
   task_annotator_.WillQueueTask("ThreadController::Task", pending_task);
 }
 
 void ThreadControllerWithMessagePumpImpl::ScheduleWork() {
-  // Continuation will be posted if necessary.
-  if (RunsTasksInCurrentSequence() && is_doing_work())
-    return;
-
   pump_->ScheduleWork();
 }
 
 void ThreadControllerWithMessagePumpImpl::SetNextDelayedDoWork(
     LazyNow* lazy_now,
     TimeTicks run_time) {
-  if (main_thread_only().next_delayed_work == run_time)
-    return;
-  main_thread_only().next_delayed_work = run_time;
-
-  if (run_time == TimeTicks::Max())
-    return;
-
-  // Continuation will be posted if necessary.
+  // Since this method must be called on the main thread, we're probably
+  // inside of DoWork() except some initialization code.
+  // DoWork() will schedule next wake-up if necessary.
   if (is_doing_work())
     return;
-
-  // |lazy_now| will be removed in this method soon.
   DCHECK_LT(time_source_->NowTicks(), run_time);
   pump_->ScheduleDelayedWork(run_time);
 }
@@ -151,9 +150,8 @@
     // Need to run new work immediately.
     pump_->ScheduleWork();
   } else if (do_work_delay != TimeDelta::Max()) {
-    SetNextDelayedDoWork(&lazy_now, lazy_now.Now() + do_work_delay);
-  } else {
-    SetNextDelayedDoWork(&lazy_now, TimeTicks::Max());
+    // Cancels any previously scheduled delayed wake-ups.
+    pump_->ScheduleDelayedWork(lazy_now.Now() + do_work_delay);
   }
 
   return task_ran;
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
index 73a942e5..d69c21f 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
@@ -13,6 +13,7 @@
 #include "base/task/sequence_manager/sequenced_task_source.h"
 #include "base/task/sequence_manager/thread_controller.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/sequence_local_storage_map.h"
 #include "base/threading/thread_task_runner_handle.h"
 
 namespace base {
@@ -27,7 +28,8 @@
       public MessagePump::Delegate,
       public RunLoop::Delegate {
  public:
-  explicit ThreadControllerWithMessagePumpImpl(const TickClock* time_source);
+  ThreadControllerWithMessagePumpImpl(std::unique_ptr<MessagePump> message_pump,
+                                      const TickClock* time_source);
   ~ThreadControllerWithMessagePumpImpl() override;
 
   // ThreadController implementation:
@@ -36,6 +38,7 @@
   void WillQueueTask(PendingTask* pending_task) override;
   void ScheduleWork() override;
   void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override;
+  void SetTimerSlack(TimerSlack timer_slack) override;
   const TickClock* GetClock() override;
   bool RunsTasksInCurrentSequence() override;
   void SetDefaultTaskRunner(
@@ -67,9 +70,6 @@
     RunLoop::NestingObserver* nesting_observer = nullptr;  // Not owned.
     std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle;
 
-    // Next delayed DoWork time for scheduling de-duplication purpose.
-    TimeTicks next_delayed_work;
-
     // Indicates that we should yield DoWork ASAP.
     bool quit_do_work = false;
 
@@ -102,6 +102,12 @@
   debug::TaskAnnotator task_annotator_;
   const TickClock* time_source_;  // Not owned.
 
+  // Required to register the current thread as a sequence.
+  base::internal::SequenceLocalStorageMap sequence_local_storage_map_;
+  std::unique_ptr<
+      base::internal::ScopedSetSequenceLocalStorageMapForCurrentThread>
+      scoped_set_sequence_local_storage_map_for_current_thread_;
+
   DISALLOW_COPY_AND_ASSIGN(ThreadControllerWithMessagePumpImpl);
 };
 
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 7f07ee0..42645bcab 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -96,6 +96,8 @@
     "scoped_environment_variable_override.h",
     "scoped_feature_list.cc",
     "scoped_feature_list.h",
+    "scoped_mock_clock_override.cc",
+    "scoped_mock_clock_override.h",
     "scoped_mock_time_message_loop_task_runner.cc",
     "scoped_mock_time_message_loop_task_runner.h",
     "scoped_path_override.cc",
diff --git a/base/test/scoped_mock_clock_override.cc b/base/test/scoped_mock_clock_override.cc
new file mode 100644
index 0000000..46cc884
--- /dev/null
+++ b/base/test/scoped_mock_clock_override.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_clock_override.h"
+
+namespace base {
+
+ScopedMockClockOverride* ScopedMockClockOverride::scoped_mock_clock_ = nullptr;
+
+ScopedMockClockOverride::ScopedMockClockOverride()
+    :  // Start the offset past zero so that it's not treated as a null value.
+      offset_(TimeDelta::FromDays(365)) {
+  DCHECK(!scoped_mock_clock_)
+      << "Nested ScopedMockClockOverrides are not supported.";
+
+  scoped_mock_clock_ = this;
+
+  time_clock_overrides_ = std::make_unique<subtle::ScopedTimeClockOverrides>(
+      &ScopedMockClockOverride::Now, &ScopedMockClockOverride::NowTicks,
+      &ScopedMockClockOverride::NowThreadTicks);
+}
+
+ScopedMockClockOverride::~ScopedMockClockOverride() {
+  scoped_mock_clock_ = nullptr;
+}
+
+Time ScopedMockClockOverride::Now() {
+  return Time() + scoped_mock_clock_->offset_;
+}
+
+TimeTicks ScopedMockClockOverride::NowTicks() {
+  return TimeTicks() + scoped_mock_clock_->offset_;
+}
+
+ThreadTicks ScopedMockClockOverride::NowThreadTicks() {
+  return ThreadTicks() + scoped_mock_clock_->offset_;
+}
+
+void ScopedMockClockOverride::Advance(TimeDelta delta) {
+  DCHECK_GT(delta, base::TimeDelta())
+      << "Monotonically increasing time may not go backwards";
+  offset_ += delta;
+}
+
+}  // namespace base
diff --git a/base/test/scoped_mock_clock_override.h b/base/test/scoped_mock_clock_override.h
new file mode 100644
index 0000000..c980502
--- /dev/null
+++ b/base/test/scoped_mock_clock_override.h
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
+#define BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
+
+namespace base {
+
+// Override the return value of Time::Now(), Time::NowFromSystemTime(),
+// TimeTicks::Now(), and ThreadTicks::Now() through a simple advanceable clock.
+//
+// This utility is intended to support tests that:
+//
+//   - Depend on large existing codebases that call TimeXYZ::Now() directly or
+//   - Have no ability to inject a TickClock into the code getting the time
+//     (e.g. integration tests in which a TickClock would be several layers
+//     removed from the test code)
+//
+// For new unit tests, developers are highly encouraged to structure new code
+// around a dependency injected base::Clock, base::TickClock, etc. to be able
+// to supply a mock time in tests without a global override.
+class ScopedMockClockOverride {
+ public:
+  ScopedMockClockOverride();
+  ~ScopedMockClockOverride();
+
+  static Time Now();
+  static TimeTicks NowTicks();
+  static ThreadTicks NowThreadTicks();
+
+  void Advance(TimeDelta delta);
+
+ private:
+  std::unique_ptr<base::subtle::ScopedTimeClockOverrides> time_clock_overrides_;
+  TimeDelta offset_;
+  static ScopedMockClockOverride* scoped_mock_clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedMockClockOverride);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
diff --git a/base/test/scoped_mock_clock_override_unittest.cc b/base/test/scoped_mock_clock_override_unittest.cc
new file mode 100644
index 0000000..f4d22b6
--- /dev/null
+++ b/base/test/scoped_mock_clock_override_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_clock_override.h"
+
+#include "base/build_time.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(ScopedMockClockOverrideTest, Time) {
+  // Choose a reference time that we know to be in the past but close to now.
+  Time build_time = GetBuildTime();
+
+  // Override is not active. All Now() methods should return a time greater than
+  // the build time.
+  EXPECT_LT(build_time, Time::Now());
+  EXPECT_GT(Time::Max(), Time::Now());
+  EXPECT_LT(build_time, Time::NowFromSystemTime());
+  EXPECT_GT(Time::Max(), Time::NowFromSystemTime());
+
+  {
+    // Set override.
+    ScopedMockClockOverride mock_clock;
+
+    EXPECT_NE(Time(), Time::Now());
+    Time start = Time::Now();
+    mock_clock.Advance(TimeDelta::FromSeconds(1));
+    EXPECT_EQ(start + TimeDelta::FromSeconds(1), Time::Now());
+  }
+
+  // All methods return real time again.
+  EXPECT_LT(build_time, Time::Now());
+  EXPECT_GT(Time::Max(), Time::Now());
+  EXPECT_LT(build_time, Time::NowFromSystemTime());
+  EXPECT_GT(Time::Max(), Time::NowFromSystemTime());
+}
+
+TEST(ScopedMockClockOverrideTest, TimeTicks) {
+  // Override is not active. All Now() methods should return a sensible value.
+  EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now());
+  EXPECT_GT(TimeTicks::Max(), TimeTicks::Now());
+  EXPECT_LT(TimeTicks::UnixEpoch() + TimeDelta::FromDays(365),
+            TimeTicks::Now());
+
+  {
+    // Set override.
+    ScopedMockClockOverride mock_clock;
+
+    EXPECT_NE(TimeTicks(), TimeTicks::Now());
+    TimeTicks start = TimeTicks::Now();
+    mock_clock.Advance(TimeDelta::FromSeconds(1));
+    EXPECT_EQ(start + TimeDelta::FromSeconds(1), TimeTicks::Now());
+  }
+
+  // All methods return real ticks again.
+  EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now());
+  EXPECT_GT(TimeTicks::Max(), TimeTicks::Now());
+  EXPECT_LT(TimeTicks::UnixEpoch() + TimeDelta::FromDays(365),
+            TimeTicks::Now());
+}
+
+TEST(ScopedMockClockOverrideTest, ThreadTicks) {
+  if (ThreadTicks::IsSupported()) {
+    ThreadTicks::WaitUntilInitialized();
+
+    // Override is not active. All Now() methods should return a sensible value.
+    ThreadTicks initial_thread_ticks = ThreadTicks::Now();
+    EXPECT_LE(initial_thread_ticks, ThreadTicks::Now());
+    EXPECT_GT(ThreadTicks::Max(), ThreadTicks::Now());
+    EXPECT_LT(ThreadTicks(), ThreadTicks::Now());
+
+    {
+      // Set override.
+      ScopedMockClockOverride mock_clock;
+
+      EXPECT_NE(ThreadTicks(), ThreadTicks::Now());
+      ThreadTicks start = ThreadTicks::Now();
+      mock_clock.Advance(TimeDelta::FromSeconds(1));
+      EXPECT_EQ(start + TimeDelta::FromSeconds(1), ThreadTicks::Now());
+    }
+
+    // All methods return real ticks again.
+    EXPECT_LE(initial_thread_ticks, ThreadTicks::Now());
+    EXPECT_GT(ThreadTicks::Max(), ThreadTicks::Now());
+    EXPECT_LT(ThreadTicks(), ThreadTicks::Now());
+  }
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index fdc7f092..5a61968 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -92,10 +92,7 @@
   proguard.config_exclusions(options.proguard_config_exclusions)
   proguard.outjar(options.output_path)
 
-  # If a jar is part of input no need to include it as library jar.
-  classpath = [
-      p for p in set(options.classpath) if p not in options.input_paths
-  ]
+  classpath = list(set(options.classpath))
   proguard.libraryjars(classpath)
   proguard.verbose(options.verbose)
   if not options.enable_dangerous_optimizations:
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 761dc18..d4339b0 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -1012,10 +1012,7 @@
       else:
         gradle['dependent_java_projects'].append(c['path'])
 
-  # TODO(tiborg): Remove creation of JNI info for type group and java_library
-  # once we can generate the JNI registration based on APK / module targets as
-  # opposed to groups and libraries.
-  if is_apk_or_module_target or options.type in ('group', 'java_library'):
+  if is_apk_or_module_target:
     config['jni'] = {}
     all_java_sources = [c['java_sources_file'] for c in all_library_deps
                         if 'java_sources_file' in c]
@@ -1171,28 +1168,23 @@
 
     # Deps to add to the compile-time classpath (but not the runtime classpath).
     # TODO(agrieve): Might be less confusing to fold these into bootclasspath.
-    javac_extra_jars = [c['unprocessed_jar_path']
-                  for c in classpath_deps.Direct('java_library')]
-    extra_jars = [c['jar_path']
+    extra_jars = [c['unprocessed_jar_path']
                   for c in classpath_deps.Direct('java_library')]
 
     if options.extra_classpath_jars:
       # These are .jars to add to javac classpath but not to runtime classpath.
-      javac_extra_jars.extend(
-          build_utils.ParseGnList(options.extra_classpath_jars))
       extra_jars.extend(build_utils.ParseGnList(options.extra_classpath_jars))
 
+    extra_jars = [p for p in extra_jars if p not in javac_classpath]
+    javac_classpath.extend(extra_jars)
+    javac_interface_classpath.extend(extra_jars)
+    javac_full_interface_classpath.extend(
+        p for p in extra_jars if p not in javac_full_classpath)
+    javac_full_classpath.extend(
+        p for p in extra_jars if p not in javac_full_classpath)
     if extra_jars:
       deps_info['extra_classpath_jars'] = extra_jars
 
-    javac_extra_jars = [p for p in javac_extra_jars if p not in javac_classpath]
-    javac_classpath.extend(javac_extra_jars)
-    javac_interface_classpath.extend(javac_extra_jars)
-    javac_full_interface_classpath.extend(
-        p for p in javac_extra_jars if p not in javac_full_classpath)
-    javac_full_classpath.extend(
-        p for p in javac_extra_jars if p not in javac_full_classpath)
-
   if is_java_target or options.type == 'android_app_bundle':
     # The classpath to use to run this target (or as an input to ProGuard).
     java_full_classpath = []
diff --git a/build/android/pylib/valgrind_tools.py b/build/android/pylib/valgrind_tools.py
index 4c27b08..431b798 100644
--- a/build/android/pylib/valgrind_tools.py
+++ b/build/android/pylib/valgrind_tools.py
@@ -4,7 +4,6 @@
 
 # pylint: disable=R0201
 
-import glob
 import logging
 import os.path
 import subprocess
@@ -12,7 +11,8 @@
 
 from devil.android import device_errors
 from devil.android.valgrind_tools import base_tool
-from pylib.constants import DIR_SOURCE_ROOT
+from pylib import constants
+
 
 
 def SetChromeTimeoutScale(device, scale):
@@ -42,17 +42,15 @@
   @classmethod
   def CopyFiles(cls, device):
     """Copies ASan tools to the device."""
-    libs = glob.glob(os.path.join(DIR_SOURCE_ROOT,
-                                  'third_party/llvm-build/Release+Asserts/',
-                                  'lib/clang/*/lib/linux/',
-                                  'libclang_rt.asan-arm-android.so'))
-    assert len(libs) == 1
+    # build/config/sanitizers/BUILD.gn puts the runtime in the build dir.
+    lib = os.path.join(constants.GetOutDirectory(),
+                       'libclang_rt.asan-arm-android.so')
     subprocess.call(
         [os.path.join(
-             DIR_SOURCE_ROOT,
+             constants.DIR_SOURCE_ROOT,
              'tools/android/asan/third_party/asan_device_setup.sh'),
          '--device', str(device),
-         '--lib', libs[0],
+         '--lib', lib,
          '--extra-options', AddressSanitizerTool.EXTRA_OPTIONS])
     device.WaitUntilFullyBooted()
 
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index ab1b52f0..63f5e24 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -396,8 +396,7 @@
   #   target: The Apk target to generate registrations for.
   #   output: Path to the generated .h file.
   #   exception_files: List of .java files that should be ignored when searching
-  #     for native methods. (optional)
-  #   namespace: Registration functions will be wrapped into this. (optional)
+  #   for native methods. (optional)
   #
   # Example
   #   generate_jni_registration("chrome_jni_registration") {
@@ -414,6 +413,9 @@
                       get_label_info(invoker.target, "name") + ".build_config"
       _rebased_build_config = rebase_path(_build_config, root_build_dir)
 
+      _rebase_exception_java_files =
+          rebase_path(invoker.exception_files, root_build_dir)
+
       script = "//base/android/jni_generator/jni_registration_generator.py"
       deps = [
         "${invoker.target}__build_config",
@@ -431,17 +433,10 @@
         "--sources_files=@FileArg($_rebased_build_config:jni:all_source)",
         "--output",
         rebase_path(invoker.output, root_build_dir),
+        "--no_register_java=$_rebase_exception_java_files",
         "--depfile",
         rebase_path(depfile, root_build_dir),
       ]
-      if (defined(invoker.exception_files)) {
-        _rebase_exception_java_files =
-            rebase_path(invoker.exception_files, root_build_dir)
-        args += [ "--no_register_java=$_rebase_exception_java_files" ]
-      }
-      if (defined(invoker.namespace)) {
-        args += [ "--namespace=${invoker.namespace}" ]
-      }
     }
   }
 
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index faa533b..7be37c7 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -45,7 +45,7 @@
     # ASAN is supported on iOS but the runtime library depends on the compiler
     # used (Chromium version of clang versus Xcode version of clang). Only copy
     # the ASAN runtime on iOS if building with Chromium clang.
-    if (is_win || is_mac || (is_ios && !use_xcode_clang)) {
+    if (is_android || is_mac || is_win || (is_ios && !use_xcode_clang)) {
       data_deps = [
         ":copy_asan_runtime",
       ]
@@ -58,8 +58,13 @@
   }
 }
 
-if ((is_mac || is_win || (is_ios && !use_xcode_clang)) && using_sanitizer) {
-  if (is_mac) {
+if ((is_android || is_mac || is_win || (is_ios && !use_xcode_clang)) &&
+    using_sanitizer) {
+  if (is_android) {
+    # All asan bots currently use 32-bit arm.
+    # If you change this, also change build/android/pylib/valgrind_tools.py.
+    _clang_rt_dso_path = "linux/libclang_rt.asan-arm-android.so"
+  } else if (is_mac) {
     _clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
   } else if (is_ios) {
     _clang_rt_dso_path = "darwin/libclang_rt.asan_iossim_dynamic.dylib"
@@ -74,9 +79,14 @@
 
   if (!is_ios) {
     copy("copy_asan_runtime") {
+      # The android runtime path contains "linux", which by default gets
+      # filtered out. Temporarily deactivate the filename filter.
+      set_sources_assignment_filter([])
       sources = [
         _clang_rt_dso_full_path,
       ]
+      set_sources_assignment_filter(sources_assignment_filter)
+
       outputs = [
         "$root_out_dir/{{source_file_part}}",
       ]
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index c07c9387..a086cd7 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-43e0834be00a65cd7f811ad3cb5c2528e456ec52
\ No newline at end of file
+5ba2f403a63325723801c92142f788bebf37f819
\ No newline at end of file
diff --git a/cc/paint/paint_record.cc b/cc/paint/paint_record.cc
index 6609e82..ac329d3 100644
--- a/cc/paint/paint_record.cc
+++ b/cc/paint/paint_record.cc
@@ -9,22 +9,28 @@
 
 namespace cc {
 
-sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
-                             const SkRect& bounds,
-                             ImageProvider* image_provider) {
+sk_sp<SkPicture> ToSkPicture(
+    sk_sp<PaintRecord> record,
+    const SkRect& bounds,
+    ImageProvider* image_provider,
+    PlaybackParams::CustomDataRasterCallback callback) {
   SkPictureRecorder recorder;
   SkCanvas* canvas = recorder.beginRecording(bounds);
   PlaybackParams params(image_provider);
+  params.custom_callback = callback;
   record->Playback(canvas, params);
   return recorder.finishRecordingAsPicture();
 }
 
-sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record,
-                                   const SkRect& bounds,
-                                   ImageProvider* image_provider) {
+sk_sp<const SkPicture> ToSkPicture(
+    sk_sp<const PaintRecord> record,
+    const SkRect& bounds,
+    ImageProvider* image_provider,
+    PlaybackParams::CustomDataRasterCallback callback) {
   SkPictureRecorder recorder;
   SkCanvas* canvas = recorder.beginRecording(bounds);
   PlaybackParams params(image_provider);
+  params.custom_callback = callback;
   record->Playback(canvas, params);
   return recorder.finishRecordingAsPicture();
 }
diff --git a/cc/paint/paint_record.h b/cc/paint/paint_record.h
index 6e0c1d7..38b878e 100644
--- a/cc/paint/paint_record.h
+++ b/cc/paint/paint_record.h
@@ -21,12 +21,16 @@
 CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(
     sk_sp<PaintRecord> record,
     const SkRect& bounds,
-    ImageProvider* image_provider = nullptr);
+    ImageProvider* image_provider = nullptr,
+    PlaybackParams::CustomDataRasterCallback callback =
+        PlaybackParams::CustomDataRasterCallback());
 
 CC_PAINT_EXPORT sk_sp<const SkPicture> ToSkPicture(
     sk_sp<const PaintRecord> record,
     const SkRect& bounds,
-    ImageProvider* image_provider = nullptr);
+    ImageProvider* image_provider = nullptr,
+    PlaybackParams::CustomDataRasterCallback callback =
+        PlaybackParams::CustomDataRasterCallback());
 
 }  // namespace cc
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 8373b3c..97e7aaf 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -119,6 +119,11 @@
 // V1 saw errors of ~0.065 between computed window and content widths.
 const float kMobileViewportWidthEpsilon = 0.15f;
 
+// We report frames and their display time to the FrameMetrics to analyze fps
+// for every |kFrameMetricsScrollReportFrequency|th scroll event after the last
+// report.
+const int kFrameMetricsScrollReportFrequency = 10;
+
 bool HasFixedPageScale(LayerTreeImpl* active_tree) {
   return active_tree->min_page_scale_factor() ==
          active_tree->max_page_scale_factor();
@@ -1908,13 +1913,17 @@
 
   active_tree_->GetViewportSelection(&metadata.selection);
 
+  // Skip recording frame metrics for android_webview
+  // (using_synchronous_renderer_compositor) scrolls because different
+  // application is handling frame presentation in android webview.
   if (active_tree_->has_presentation_callbacks() ||
-      settings_.always_request_presentation_time) {
+      settings_.always_request_presentation_time ||
+      (scroll_events_after_reporting_ == 0 && CurrentlyScrollingNode() &&
+       !settings_.using_synchronous_renderer_compositor)) {
     metadata.request_presentation_feedback = true;
     frame_token_infos_.emplace_back(metadata.frame_token,
                                     CurrentBeginFrameArgs().frame_time,
                                     active_tree_->TakePresentationCallbacks());
-
     DCHECK_LE(frame_token_infos_.size(), 25u);
   }
 
@@ -2522,6 +2531,7 @@
   gfx::Transform surface_to_root_transform = layer->ScreenSpaceTransform();
   surface_to_root_transform.Scale(SK_MScalar1 / device_scale_factor,
                                   SK_MScalar1 / device_scale_factor);
+  surface_to_root_transform.FlattenTo2d();
   // TODO(sunxd): Avoid losing precision by not using inverse if possible.
   bool ok = surface_to_root_transform.GetInverse(&hit_test_region->transform);
   // Note: If |ok| is false, the |transform| is set to the identity before
@@ -4409,6 +4419,14 @@
   DistributeScrollDelta(scroll_state);
   browser_controls_offset_manager_->ScrollEnd();
   ClearCurrentlyScrollingNode();
+
+  // At the end of a scrolling event, increases |scroll_events_after_reporting_|
+  // by 1. If it is the |kFrameMetricsScrollReportFrequency| scrolling event
+  // after the previous report to the frame metrics, then
+  // |scroll_events_after_reporting_| becomes 0 and the data will be reported
+  // back the frame metrics.
+  scroll_events_after_reporting_ =
+      (scroll_events_after_reporting_ + 1) % kFrameMetricsScrollReportFrequency;
 }
 
 void LayerTreeHostImpl::ScrollEnd(ScrollState* scroll_state, bool should_snap) {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index a910202..df5170d 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -1102,6 +1102,9 @@
   ui::FrameMetrics frame_metrics_;
   ui::SkippedFrameTracker skipped_frame_tracker_;
   bool is_animating_for_snap_;
+  // The number of scroll events happened after the last report to frame
+  // metrics.
+  int scroll_events_after_reporting_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
 };
diff --git a/chrome/VERSION b/chrome/VERSION
index 327b3b4..d509745 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=70
 MINOR=0
-BUILD=3517
+BUILD=3518
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 6f3ab1b..0bd8aa2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -348,6 +348,7 @@
   srcjar_deps += feed_srcjar_deps
 
   if (enable_vr) {
+    java_files += chrome_vr_java_sources
     deps += [
       "//device/vr:java",
       "//third_party/gvr-android-keyboard:kb_java",
@@ -680,7 +681,6 @@
     "//base:base_java_test_support",
     "//chrome/android:app_hooks_java",
     "//chrome/android:chrome_java",
-    "//chrome/browser/android/vr:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/policy/android:policy_java",
     "//content/public/android:content_java",
@@ -930,11 +930,6 @@
   deps = [
     ":chrome_jni_registration($default_toolchain)",
   ]
-  if (enable_vr) {
-    sources += [ "../browser/android/vr/register_jni.cc" ]
-    deps +=
-        [ "//chrome/browser/android/vr:jni_registration($default_toolchain)" ]
-  }
 }
 
 chrome_shared_library("libchromefortest") {
@@ -950,11 +945,6 @@
     "//components/heap_profiling:test_support",
     "//content/public/test/android:content_native_test_support",
   ]
-  if (enable_vr) {
-    sources += [ "../browser/android/vr/register_jni.cc" ]
-    deps +=
-        [ "//chrome/browser/android/vr:jni_registration($default_toolchain)" ]
-  }
 }
 
 # Ensure that .pak files are built only once (build them in the default
@@ -962,21 +952,21 @@
 # is generated from Java code so it just needs to be generated once.
 if (current_toolchain == default_toolchain) {
   generate_jni_registration("chrome_jni_registration") {
-    target = ":chrome_public_base_module_java"
+    target = ":chrome_public_apk"
     output = "$root_gen_dir/chrome/browser/android/${target_name}.h"
     exception_files = jni_exception_files
   }
 
   generate_jni_registration("chrome_jni_for_test_registration") {
     testonly = true
-    target = ":chrome_public_base_module_java_for_test"
+    target = ":chrome_public_apk_for_test"
     output = "$root_gen_dir/chrome/browser/android/${target_name}.h"
     exception_files = jni_exception_files
   }
 
   generate_jni_registration("chrome_sync_shell_jni_registration") {
     testonly = true
-    target = ":chrome_sync_shell_java"
+    target = ":chrome_sync_shell_apk"
     output = "$root_gen_dir/chrome/browser/android/${target_name}.h"
     exception_files = jni_exception_files
   }
@@ -1119,9 +1109,6 @@
     sources = [
       "../browser/android/monochrome_entry_point.cc",
     ]
-    if (enable_vr) {
-      sources += [ "../browser/android/vr/register_jni_monochrome.cc" ]
-    }
     deps = [
       "//android_webview:common",
       "//chrome:chrome_android_core",
@@ -1167,62 +1154,17 @@
   if (chromium_linker_supported && use_lld) {
     configs += [ "//build/config/android:lld_pack_relocations" ]
   }
-  if (enable_vr) {
-    sources += [ "../browser/android/vr/register_jni.cc" ]
-    deps +=
-        [ "//chrome/browser/android/vr:jni_registration($default_toolchain)" ]
-  }
-}
-
-# Java libraries that go into each public chrome APK and base module. The chrome
-# JNI registration is generated based on this target.
-# TODO(tiborg): Remove the following three groups once we have a APK / module
-# target that contain exactly the grouped java libraries.
-java_group("chrome_public_base_module_java") {
-  deps = [
-    ":app_hooks_java",
-    ":chrome_java",
-  ]
-}
-
-# Similar to chrome_public_base_module_java but for Java libraries that go into
-# the public chrome test APK.
-java_group("chrome_public_base_module_java_for_test") {
-  testonly = true
-  deps = [
-    ":browser_java_test_support",
-    ":chrome_public_base_module_java",
-    "//chrome/browser/android/metrics:ukm_utils_java",
-    "//components/heap_profiling:heap_profiling_java_test_support",
-    "//content/public/test/android:content_java_test_support",
-    "//third_party/android_tools:android_test_mock_java",
-  ]
-}
-
-# Similar to chrome_public_base_module_java but for Java libraries that go into
-# the chrome sync shell APK.
-android_library("chrome_sync_shell_java") {
-  # This exists here rather than in chrome_sync_shell_test_apk for JNI
-  # registration to be able to find the native side functions.
-  java_files = [ "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java" ]
-  deps = [
-    ":chrome_public_base_module_java",
-
-    # This exists here because com.google.protobuf.nano is needed in tests,
-    # but that code is stripped out via proguard. Adding this deps adds
-    # usages and prevents removal of the proto code.
-    "//components/sync:test_support_proto_java",
-    "//third_party/android_protobuf:protobuf_nano_javalib",
-  ]
 }
 
 # Dependencies that are common to any chrome_public derivative targets, as well
 # as to chrome_sync_shell_apk.
 _chrome_public_and_sync_shell_shared_deps = [
+  ":app_hooks_java",
+  ":chrome_java",
   ":chrome_public_apk_resources",
-  ":chrome_public_base_module_java",
   ":chrome_public_non_pak_assets",
   ":chrome_public_pak_assets",
+  "//base:base_java",
 ]
 
 generate_jni("test_support_jni_headers") {
@@ -1361,8 +1303,13 @@
   if (_add_unwind_tables_in_chrome_public_apk) {
     shared_library_for_unwind_asset = "chromefortest"
   }
-  deps = _chrome_public_and_sync_shell_shared_deps +
-         [ ":chrome_public_base_module_java_for_test" ]
+  deps = _chrome_public_and_sync_shell_shared_deps + [
+           ":browser_java_test_support",
+           "//chrome/browser/android/metrics:ukm_utils_java",
+           "//components/heap_profiling:heap_profiling_java_test_support",
+           "//content/public/test/android:content_java_test_support",
+           "//third_party/android_tools:android_test_mock_java",
+         ]
   if (!is_java_debug) {
     proguard_configs = [ "//chrome/android/java/apk_for_test.flags" ]
   }
@@ -1454,10 +1401,19 @@
   apk_name = "ChromeSyncShell"
   shared_libraries = [ ":chrome_sync_shell" ]
 
-  deps = _chrome_public_and_sync_shell_shared_deps + [
-           ":chrome_sync_shell_apk_template_resources",
-           ":chrome_sync_shell_java",
-         ]
+  # This exists here rather than in chrome_sync_shell_test_apk for JNI
+  # registration to be able to find the native side functions.
+  java_files = [ "sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java" ]
+  deps =
+      _chrome_public_and_sync_shell_shared_deps + [
+        ":chrome_sync_shell_apk_template_resources",
+
+        # This exists here because com.google.protobuf.nano is needed in tests,
+        # but that code is stripped out via proguard. Adding this deps adds
+        # usages and prevents removal of the proto code.
+        "//components/sync:test_support_proto_java",
+        "//third_party/android_protobuf:protobuf_nano_javalib",
+      ]
 }
 
 chrome_public_test_apk_manifest =
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 353441c..44ae5f0 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -170,10 +170,6 @@
         invoker.add_unwind_tables_in_apk) {
       deps += [ ":$_unwind_asset" ]
     }
-
-    if (enable_vr) {
-      deps += [ "//chrome/browser/android/vr:java" ]
-    }
   }
 }
 
diff --git a/chrome/android/java/res/layout/button_preference_button.xml b/chrome/android/java/res/layout/button_preference_button.xml
index d5dd9ab..46284baa 100644
--- a/chrome/android/java/res/layout/button_preference_button.xml
+++ b/chrome/android/java/res/layout/button_preference_button.xml
@@ -14,5 +14,5 @@
     android:layout_width="wrap_content"
     android:minHeight="40dp"
     android:focusable="false"
-    android:textColor="@android:color/white"
+    android:textAppearance="@style/WhiteButtonText"
     app:buttonColor="@color/pref_accent_color" />
diff --git a/chrome/android/java/res/layout/default_search_engine_first_run_fragment.xml b/chrome/android/java/res/layout/default_search_engine_first_run_fragment.xml
index 37c7c4c..a8d2b40d 100644
--- a/chrome/android/java/res/layout/default_search_engine_first_run_fragment.xml
+++ b/chrome/android/java/res/layout/default_search_engine_first_run_fragment.xml
@@ -63,8 +63,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/search_engine_dialog_footer"
-        android:textColor="@color/descriptive_text_color"
-        android:textSize="@dimen/text_size_medium"
+        android:textAppearance="@style/BlackBody"
         android:padding="@dimen/signin_chooser_padding" />
 
     <!--suppress ButtonStyle -->
@@ -79,9 +78,7 @@
         android:paddingStart="@dimen/fre_button_padding"
         android:paddingEnd="@dimen/fre_button_padding"
         android:text="@string/ok"
-        android:textAllCaps="true"
-        android:textColor="@android:color/white"
-        android:textSize="14sp"
+        android:textAppearance="@style/WhiteButtonText"
         app:buttonColor="@color/light_active_color"
         app:buttonRaised="false" />
 
diff --git a/chrome/android/java/res/layout/explore_sites_category_tile_view.xml b/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
similarity index 100%
rename from chrome/android/java/res/layout/explore_sites_category_tile_view.xml
rename to chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
diff --git a/chrome/android/java/res/layout/explore_sites_section.xml b/chrome/android/java/res/layout/experimental_explore_sites_section.xml
similarity index 100%
rename from chrome/android/java/res/layout/explore_sites_section.xml
rename to chrome/android/java/res/layout/experimental_explore_sites_section.xml
diff --git a/chrome/android/java/res/layout/item_chooser_dialog.xml b/chrome/android/java/res/layout/item_chooser_dialog.xml
index aba9003..c0496a6 100644
--- a/chrome/android/java/res/layout/item_chooser_dialog.xml
+++ b/chrome/android/java/res/layout/item_chooser_dialog.xml
@@ -20,7 +20,7 @@
         android:paddingBottom="8dp"
         android:paddingStart="16dp"
         android:paddingEnd="16dp"
-        android:textSize="16sp" />
+        android:textAppearance="@style/BlackHint1" />
 
     <!-- The "no item found" message. -->
     <org.chromium.ui.widget.TextViewWithClickableSpans
@@ -30,7 +30,7 @@
         android:layout_marginTop="8dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="16dp"
-        android:textSize="16sp"
+        android:textAppearance="@style/BlackHint1"
         android:visibility="gone" />
 
     <!-- A layout containing a spinning progress bar that gets replaced with a
@@ -66,7 +66,7 @@
         android:layout_marginTop="12dp"
         android:paddingStart="16dp"
         android:paddingEnd="16dp"
-        android:textSize="14sp" />
+        android:textAppearance="@style/BlackBody" />
 
     <!-- Button row. -->
     <org.chromium.ui.widget.ButtonCompat
@@ -78,7 +78,6 @@
         android:layout_marginEnd="12dp"
         android:paddingStart="16dp"
         android:paddingEnd="16dp"
-        android:textAllCaps="true"
-        android:textColor="#fff"
+        android:textAppearance="@style/WhiteButtonText"
         app:buttonColor="@color/pref_accent_color" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/navigation_popup_item.xml b/chrome/android/java/res/layout/navigation_popup_item.xml
index d9b2b69c..83bd45d 100644
--- a/chrome/android/java/res/layout/navigation_popup_item.xml
+++ b/chrome/android/java/res/layout/navigation_popup_item.xml
@@ -7,7 +7,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/navigation_popup_item_height"
+    android:layout_height="wrap_content"
     android:paddingStart="@dimen/navigation_popup_default_padding"
     android:paddingEnd="@dimen/navigation_popup_default_padding"
     android:gravity="center_vertical"
@@ -32,9 +32,11 @@
 
     <TextView
         android:id="@+id/entry_title"
+        android:gravity="center_vertical"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/navigation_popup_default_padding"
+        android:minHeight="@dimen/navigation_popup_item_height"
         android:textAppearance="@style/BlackTitle1"
         android:singleLine="true" />
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index eb755b6..fe391b0d 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -58,8 +58,7 @@
             android:gravity="center_vertical"
             android:inputType="text"
             android:singleLine="true"
-            android:textSize="@dimen/location_bar_url_text_size"
-            android:textColorHint="@color/search_box_hint" />
+            android:textAppearance="@style/TextAppearance.NewTabPageSearchBoxText" />
         <org.chromium.chrome.browser.widget.TintedImageView
             android:id="@+id/voice_search_button"
             android:layout_width="wrap_content"
@@ -92,7 +91,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:inflatedId="@+id/explore_sites"
-        android:layout="@layout/explore_sites_section" />
+        android:layout="@layout/experimental_explore_sites_section" />
 
     <!-- Site suggestion tile grid placeholder -->
     <ViewStub
diff --git a/chrome/android/java/res/layout/page_info.xml b/chrome/android/java/res/layout/page_info.xml
index cc2ef7f3..6374953 100644
--- a/chrome/android/java/res/layout/page_info.xml
+++ b/chrome/android/java/res/layout/page_info.xml
@@ -29,8 +29,7 @@
             android:lineSpacingExtra="6dp"
             android:paddingTop="16dp"
             android:textAlignment="viewStart"
-            android:textColor="@color/url_emphasis_default_text"
-            android:textSize="16sp"/>
+            android:textAppearance="@style/BlackTitle1" />
 
         <TextView
             android:id="@+id/page_info_connection_summary"
@@ -62,8 +61,7 @@
         android:paddingEnd="@dimen/page_info_popup_button_padding_sides"
         android:paddingStart="@dimen/page_info_popup_button_padding_sides"
         android:text="@string/page_info_instant_app_button"
-        android:textSize="14sp"
-        android:textColor="@android:color/white"
+        android:textAppearance="@style/WhiteButtonText"
         app:buttonRaised="false"
         app:buttonColor="@color/app_banner_install_button_bg" />
 
diff --git a/chrome/android/java/res/layout/sad_tab.xml b/chrome/android/java/res/layout/sad_tab.xml
index b79b4ac1..9c9a89e 100644
--- a/chrome/android/java/res/layout/sad_tab.xml
+++ b/chrome/android/java/res/layout/sad_tab.xml
@@ -72,7 +72,7 @@
             android:id="@+id/sad_tab_button"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:textColor="#fff"
+            android:textAppearance="@style/WhiteButtonText"
             android:minWidth="222dp"
             app:buttonColor="@color/light_active_color"
             android:layout_gravity="end" />
diff --git a/chrome/android/java/res/layout/sync_promo_view.xml b/chrome/android/java/res/layout/sync_promo_view.xml
index 18f307b..50cfb8c 100644
--- a/chrome/android/java/res/layout/sync_promo_view.xml
+++ b/chrome/android/java/res/layout/sync_promo_view.xml
@@ -44,8 +44,7 @@
                 android:id="@+id/sign_in"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:textAllCaps="true"
-                android:textAppearance="@style/WhiteLink"
+                android:textAppearance="@style/WhiteButtonText"
                 app:buttonColor="@color/light_active_color" />
         </LinearLayout>
 
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index f7807130..931d0ea 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -616,10 +616,14 @@
         <item name="android:textAppearance">@style/BlueLink2</item>
     </style>
 
-    <!-- New tab page RecyclerView overscroll color -->
+    <!-- New Tab Page -->
     <style name="NewTabPageRecyclerView">
         <item name="android:colorEdgeEffect" tools:targetApi="21">@color/google_grey_300</item>
     </style>
+    <style name="TextAppearance.NewTabPageSearchBoxText">
+        <item name="android:textSize">@dimen/location_bar_url_text_size</item>
+        <item name="android:textColorHint">@color/search_box_hint</item>
+    </style>
 
     <!-- Modern List Item -->
     <style name="ListItemContainer">
@@ -771,7 +775,7 @@
         <item name="android:focusable">true</item>
         <item name="android:textAppearance">@style/BlueButtonText1</item>
         <item name="android:padding">16dp</item>
-    </style>
+      </style>
     <!-- TODO(https://crbug.com/850138): Confirm with UX whether this should be a one-off text
          appearance or a pre-defined text appearance. -->
     <style name="TextAppearance.IncognitoNewTabLearnMoreLinkModern">
@@ -780,7 +784,6 @@
     </style>
 
     <!-- Picker Dialog animations -->
-
     <style name="PickerDialogAnimation">
         <item name="android:windowEnterAnimation">@anim/design_bottom_sheet_slide_in</item>
         <item name="android:windowExitAnimation">@null</item>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 437a8cb..49625ea 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -593,5 +593,6 @@
     <dimen name="navigation_popup_width">312dp</dimen>
     <dimen name="navigation_popup_item_height">56dp</dimen>
     <dimen name="navigation_popup_default_padding">16dp</dimen>
+    <dimen name="navigation_popup_top_padding">8dp</dimen>
     <dimen name="navigation_popup_favicon_bg_size">36dp</dimen>
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
index 044fb8a..53b38ed4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
@@ -260,7 +260,7 @@
     }
 
     private class NavigationAdapter extends BaseAdapter {
-        private boolean mInReverseOrder;
+        boolean mInReverseOrder;
 
         public void reverseOrder() {
             mInReverseOrder = true;
@@ -299,6 +299,8 @@
     }
 
     private class NewNavigationAdapter extends NavigationAdapter {
+        private Integer mTopPadding;
+
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             EntryViewHolder viewHolder;
@@ -306,6 +308,7 @@
                 LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                 convertView = inflater.inflate(R.layout.navigation_popup_item, parent, false);
                 viewHolder = new EntryViewHolder();
+                viewHolder.mContainer = convertView;
                 viewHolder.mImageView = convertView.findViewById(R.id.favicon_img);
                 viewHolder.mTextView = convertView.findViewById(R.id.entry_title);
                 convertView.setTag(viewHolder);
@@ -317,11 +320,23 @@
             setViewText(entry, viewHolder.mTextView);
             viewHolder.mImageView.setImageBitmap(entry.getFavicon());
 
+            if (mInReverseOrder) {
+                View container = viewHolder.mContainer;
+                if (mTopPadding == null) {
+                    mTopPadding = container.getResources().getDimensionPixelSize(
+                            R.dimen.navigation_popup_top_padding);
+                }
+                viewHolder.mContainer.setPadding(container.getPaddingLeft(),
+                        position == 0 ? mTopPadding : 0, container.getPaddingRight(),
+                        container.getPaddingBottom());
+            }
+
             return convertView;
         }
     }
 
     private static class EntryViewHolder {
+        View mContainer;
         ImageView mImageView;
         TextView mTextView;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
index 78010fcd..d748af6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
@@ -64,6 +64,7 @@
 
     @Override
     public void keyboardVisibilityChanged(boolean isShowing) {
+        if (isShowing) closeActiveTab();
         mIsKeyboardVisible = isShowing;
         updateVisibility();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityUi.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityUi.java
new file mode 100644
index 0000000..07dd9db
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityUi.java
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.browserservices;
+
+import org.chromium.chrome.browser.fullscreen.BrowserStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.Tab;
+
+/**
+ * Class to handle the state and logic for CustomTabActivity to do with Trusted Web Activities.
+ */
+public class TrustedWebActivityUi {
+    private boolean mInTrustedWebActivity;
+
+    /**
+     * A {@link BrowserControlsVisibilityDelegate} that disallows showing the Browser Controls when
+     * we are in a Trusted Web Activity.
+     */
+    private final BrowserControlsVisibilityDelegate mInTwaVisibilityDelegate =
+            new BrowserControlsVisibilityDelegate() {
+                @Override
+                public boolean canShowBrowserControls() {
+                    return !mInTrustedWebActivity;
+                }
+
+                @Override
+                public boolean canAutoHideBrowserControls() {
+                    return true;
+                }
+            };
+
+    /**
+     * Gets a {@link BrowserControlsVisibilityDelegate} that will hide/show the Custom Tab toolbar
+     * on verification/leaving the verified origin.
+     */
+    public BrowserControlsVisibilityDelegate getBrowserControlsVisibilityDelegate() {
+        return mInTwaVisibilityDelegate;
+    }
+
+    /**
+     * Updates the UI appropriately for whether or not Trusted Web Activity mode is enabled.
+     */
+    public void setTrustedWebActivityMode(boolean enabled, Tab tab,
+            BrowserStateBrowserControlsVisibilityDelegate delegate) {
+        mInTrustedWebActivity = enabled;
+
+        // Force showing the controls for a bit when leaving Trusted Web Activity mode.
+        if (!enabled) delegate.showControlsTransient();
+
+        // Reflect the browser controls update in the Tab.
+        tab.updateFullscreenEnabledState();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 955f2e5f..4bc4d43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -58,6 +58,7 @@
 import org.chromium.chrome.browser.autofill_assistant.AssistantUiController;
 import org.chromium.chrome.browser.browserservices.BrowserSessionContentHandler;
 import org.chromium.chrome.browser.browserservices.BrowserSessionContentUtils;
+import org.chromium.chrome.browser.browserservices.TrustedWebActivityUi;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.customtabs.dynamicmodule.ActivityDelegate;
 import org.chromium.chrome.browser.customtabs.dynamicmodule.ActivityHostImpl;
@@ -66,7 +67,7 @@
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
-import org.chromium.chrome.browser.fullscreen.BrowserStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.gsa.GSAState;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.page_info.PageInfoController;
@@ -97,7 +98,6 @@
 import org.chromium.content_public.browser.NavigationEntry;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.PageTransition;
-import org.chromium.ui.base.WindowAndroid;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -158,6 +158,8 @@
     /** Adds and removes observers from tabs when needed. */
     private final TabObserverRegistrar mTabObserverRegistrar = new TabObserverRegistrar();
 
+    private final TrustedWebActivityUi mTrustedWebActivityUi = new TrustedWebActivityUi();
+
     private String mSpeculatedUrl;
 
     private boolean mUsingHiddenTab;
@@ -185,27 +187,6 @@
     private boolean mModuleOnResumePending;
     private boolean mHasSetOverlayView;
 
-    private static class CustomTabCreator extends ChromeTabCreator {
-        private final boolean mSupportsUrlBarHiding;
-        private final boolean mIsOpenedByChrome;
-        private final BrowserStateBrowserControlsVisibilityDelegate mVisibilityDelegate;
-
-        public CustomTabCreator(
-                ChromeActivity activity, WindowAndroid nativeWindow, boolean incognito,
-                boolean supportsUrlBarHiding, boolean isOpenedByChrome) {
-            super(activity, nativeWindow, incognito);
-            mSupportsUrlBarHiding = supportsUrlBarHiding;
-            mIsOpenedByChrome = isOpenedByChrome;
-            mVisibilityDelegate = activity.getFullscreenManager().getBrowserVisibilityDelegate();
-        }
-
-        @Override
-        public TabDelegateFactory createDefaultTabDelegateFactory() {
-            return new CustomTabDelegateFactory(
-                    mSupportsUrlBarHiding, mIsOpenedByChrome, mVisibilityDelegate);
-        }
-    }
-
     private TabModelObserver mCloseActivityWhenEmptyTabModelObserver = new EmptyTabModelObserver() {
         @Override
         public void didCloseTab(int tabId, boolean incognito) {
@@ -431,16 +412,26 @@
     }
 
     @Override
-    protected Pair<CustomTabCreator, CustomTabCreator> createTabCreators() {
-        return Pair.create(
-                new CustomTabCreator(
-                        this, getWindowAndroid(), false,
-                        mIntentDataProvider.shouldEnableUrlBarHiding(),
-                        mIntentDataProvider.isOpenedByChrome()),
-                new CustomTabCreator(
-                        this, getWindowAndroid(), true,
-                        mIntentDataProvider.shouldEnableUrlBarHiding(),
-                        mIntentDataProvider.isOpenedByChrome()));
+    protected Pair<ChromeTabCreator, ChromeTabCreator> createTabCreators() {
+        return Pair.create(createTabCreator(false), createTabCreator(true));
+    }
+
+    private ChromeTabCreator createTabCreator(boolean incognito) {
+        return new ChromeTabCreator(this, getWindowAndroid(), incognito) {
+            @Override
+            public TabDelegateFactory createDefaultTabDelegateFactory() {
+                return createCustomTabDelegateFactory();
+            }
+        };
+    }
+
+    private CustomTabDelegateFactory createCustomTabDelegateFactory() {
+        return new CustomTabDelegateFactory(mIntentDataProvider.shouldEnableUrlBarHiding(),
+                mIntentDataProvider.isOpenedByChrome(),
+                new ComposedBrowserControlsVisibilityDelegate(
+                        getFullscreenManager().getBrowserVisibilityDelegate(),
+                        mTrustedWebActivityUi.getBrowserControlsVisibilityDelegate()
+                ));
     }
 
     @Override
@@ -486,10 +477,7 @@
         if (mUsingHiddenTab) {
             TabReparentingParams params =
                     (TabReparentingParams) AsyncTabParamsManager.remove(mMainTab.getId());
-            mMainTab.attachAndFinishReparenting(this,
-                    new CustomTabDelegateFactory(mIntentDataProvider.shouldEnableUrlBarHiding(),
-                            mIntentDataProvider.isOpenedByChrome(),
-                            getFullscreenManager().getBrowserVisibilityDelegate()),
+            mMainTab.attachAndFinishReparenting(this, createCustomTabDelegateFactory(),
                     (params == null ? null : params.getFinalizeCallback()));
         }
 
@@ -654,12 +642,7 @@
         } else {
             tab.setAppAssociatedWith(mConnection.getClientPackageNameForSession(mSession));
         }
-        tab.initialize(
-                webContents, getTabContentManager(),
-                new CustomTabDelegateFactory(
-                        mIntentDataProvider.shouldEnableUrlBarHiding(),
-                        mIntentDataProvider.isOpenedByChrome(),
-                        getFullscreenManager().getBrowserVisibilityDelegate()),
+        tab.initialize(webContents, getTabContentManager(), createCustomTabDelegateFactory(),
                 false, false);
 
         if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 6d26fed..ef8894ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -18,7 +18,6 @@
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
-import org.chromium.chrome.browser.fullscreen.BrowserStateBrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
@@ -184,7 +183,7 @@
 
     private final boolean mShouldHideBrowserControls;
     private final boolean mIsOpenedByChrome;
-    private final BrowserStateBrowserControlsVisibilityDelegate mBrowserStateVisibilityDelegate;
+    private final BrowserControlsVisibilityDelegate mBrowserStateVisibilityDelegate;
 
     private ExternalNavigationDelegateImpl mNavigationDelegate;
     private ExternalNavigationHandler mNavigationHandler;
@@ -196,7 +195,7 @@
      *                           with browser actions (as opposed to tab state).
      */
     public CustomTabDelegateFactory(boolean shouldHideBrowserControls, boolean isOpenedByChrome,
-            BrowserStateBrowserControlsVisibilityDelegate visibilityDelegate) {
+            BrowserControlsVisibilityDelegate visibilityDelegate) {
         mShouldHideBrowserControls = shouldHideBrowserControls;
         mIsOpenedByChrome = isOpenedByChrome;
         mBrowserStateVisibilityDelegate = visibilityDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
similarity index 94%
rename from chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java
rename to chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
index 5806424..60bf266 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
@@ -23,7 +23,7 @@
  * The View representing a single explore sites category.
  * Consists of a large image icon over descriptive text.
  */
-public class ExploreSitesCategoryTileView extends LinearLayout {
+public class ExperimentalExploreSitesCategoryTileView extends LinearLayout {
     /** The data represented by this tile. */
     private ExploreSitesCategoryTile mCategoryData;
 
@@ -37,7 +37,7 @@
     private int mIconHeightPx;
 
     /** Constructor for inflating from XML. */
-    public ExploreSitesCategoryTileView(Context context, AttributeSet attrs) {
+    public ExperimentalExploreSitesCategoryTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mResources = context.getResources();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
similarity index 86%
rename from chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
rename to chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
index 156e8425..5165aaf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
@@ -23,7 +23,7 @@
  * Describes a portion of UI responsible for rendering a group of categories.
  * It abstracts general tasks related to initializing and fetching data for the UI.
  */
-public class ExploreSitesSection {
+public class ExperimentalExploreSitesSection {
     private static final int MAX_TILES = 3;
 
     private Profile mProfile;
@@ -31,7 +31,7 @@
     private View mExploreSection;
     private LinearLayout mCategorySection;
 
-    public ExploreSitesSection(
+    public ExperimentalExploreSitesSection(
             View view, Profile profile, SuggestionsNavigationDelegate navigationDelegate) {
         mProfile = profile;
         mExploreSection = view;
@@ -72,10 +72,11 @@
             tileCount++;
             if (tileCount > MAX_TILES) break;
 
-            final ExploreSitesCategoryTileView tileView =
-                    (ExploreSitesCategoryTileView) LayoutInflater.from(mExploreSection.getContext())
-                            .inflate(R.layout.explore_sites_category_tile_view, mCategorySection,
-                                    false);
+            final ExperimentalExploreSitesCategoryTileView tileView =
+                    (ExperimentalExploreSitesCategoryTileView) LayoutInflater
+                            .from(mExploreSection.getContext())
+                            .inflate(R.layout.experimental_explore_sites_category_tile_view,
+                                    mCategorySection, false);
 
             tileView.initialize(tile, tileWidth);
             mCategorySection.addView(tileView);
@@ -88,7 +89,7 @@
         }
     }
 
-    private void onIconRetrieved(ExploreSitesCategoryTileView tileView, Bitmap icon) {
+    private void onIconRetrieved(ExperimentalExploreSitesCategoryTileView tileView, Bitmap icon) {
         tileView.updateIcon(icon);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index e69f8ef..1e03115 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -30,7 +30,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
-import org.chromium.chrome.browser.explore_sites.ExploreSitesSection;
+import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
@@ -83,7 +83,7 @@
     @Nullable
     private View mExploreSectionView; // View is null if explore flag is disabled.
     @Nullable
-    private ExploreSitesSection mExploreSection; // Null when explore sites disabled.
+    private ExperimentalExploreSitesSection mExploreSection; // Null when explore sites disabled.
 
     private OnSearchBoxScrollListener mSearchBoxScrollListener;
 
@@ -225,7 +225,7 @@
         mSiteSectionViewHolder.bindDataSource(mTileGroup, tileRenderer);
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLORE_SITES)) {
-            mExploreSection = new ExploreSitesSection(
+            mExploreSection = new ExperimentalExploreSitesSection(
                     mExploreSectionView, profile, mManager.getNavigationDelegate());
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index cbf0c10..6ead434 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -2815,6 +2815,10 @@
         if (mExperimentalButton == null) {
             ViewStub viewStub = findViewById(R.id.experimental_button_stub);
             mExperimentalButton = (TintedImageButton) viewStub.inflate();
+
+            if (FeatureUtilities.isBottomToolbarEnabled()) {
+                mExperimentalButton.setPadding(0, 0, 0, 0);
+            }
         } else {
             assert mExperimentalButton.getVisibility()
                     == View.GONE : "#disableExperimentalButton() should be called first.";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
index a140c66..7b18b956 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser.vr;
 
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.chrome.R;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -14,7 +11,6 @@
  * Instantiates the VR delegates. If the VR module is not available this provider will
  * instantiate a fallback implementation.
  */
-@JNINamespace("vr")
 public class VrModuleProvider {
     private static VrDelegateProvider sDelegateProvider;
     private static final List<VrModeObserver> sVrModeObservers = new ArrayList<>();
@@ -53,12 +49,6 @@
         for (VrModeObserver observer : sVrModeObservers) observer.onExitVr();
     }
 
-    // TODO(crbug.com/870055): JNI should be registered in the shared VR library's JNI_OnLoad
-    // function. Do this once we have a shared VR library.
-    /* package */ static void registerJni() {
-        nativeRegisterJni();
-    }
-
     private static VrDelegateProvider getDelegateProvider() {
         if (sDelegateProvider == null) {
             try {
@@ -75,19 +65,4 @@
     }
 
     private VrModuleProvider() {}
-
-    // TODO(crbug/870056): Move resources into VR DFM.
-    private void silenceLintErrors() {
-        int[] res = new int[] {
-                R.string.vr_shell_feedback_infobar_feedback_button,
-                R.string.vr_shell_feedback_infobar_description,
-                R.string.vr_services_check_infobar_install_text,
-                R.string.vr_services_check_infobar_update_text,
-                R.string.vr_services_check_infobar_install_button,
-                R.string.vr_services_check_infobar_update_button, R.anim.stay_hidden,
-                R.drawable.vr_services,
-        };
-    }
-
-    private static native void nativeRegisterJni();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
index 06d07c3..58e8ff77 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
@@ -364,7 +364,6 @@
      * Called when the native library is first available.
      */
     public static void onNativeLibraryAvailable() {
-        VrModuleProvider.registerJni();
         nativeOnLibraryAvailable();
     }
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 5a42d9b..d9e4848 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -168,6 +168,7 @@
   "java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java",
   "java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityClient.java",
   "java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityDisclosure.java",
+  "java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityUi.java",
   "java/src/org/chromium/chrome/browser/browserservices/UkmRecorder.java",
   "java/src/org/chromium/chrome/browser/browserservices/VerificationState.java",
   "java/src/org/chromium/chrome/browser/browsing_data/UrlFilters.java",
@@ -534,10 +535,10 @@
   "java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java",
   "java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java",
   "java/src/org/chromium/chrome/browser/engagement/SiteEngagementService.java",
+  "java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java",
+  "java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTile.java",
-  "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java",
-  "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java",
   "java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java",
   "java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java",
   "java/src/org/chromium/chrome/browser/externalauth/VerifiedHandler.java",
@@ -1622,6 +1623,42 @@
   "java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java",
 ]
 
+chrome_vr_java_sources = [
+  "java/src/org/chromium/chrome/browser/component_updater/VrAssetsComponentInstaller.java",
+  "java/src/org/chromium/chrome/browser/vr/AndroidUiGestureTarget.java",
+  "java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java",
+  "java/src/org/chromium/chrome/browser/vr/keyboard/BuildConstants.java",
+  "java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java",
+  "java/src/org/chromium/chrome/browser/vr/keyboard/TextEditAction.java",
+  "java/src/org/chromium/chrome/browser/vr/keyboard/VrInputMethodManagerWrapper.java",
+  "java/src/org/chromium/chrome/browser/vr/EmptySniffingVrViewContainer.java",
+  "java/src/org/chromium/chrome/browser/vr/NoopCanvas.java",
+  "java/src/org/chromium/chrome/browser/vr/OnDispatchTouchEventCallback.java",
+  "java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java",
+  "java/src/org/chromium/chrome/browser/vr/VrCancelAnimationActivity.java",
+  "java/src/org/chromium/chrome/browser/vr/VrCompositorSurfaceManager.java",
+  "java/src/org/chromium/chrome/browser/vr/VrCoreInfo.java",
+  "java/src/org/chromium/chrome/browser/vr/VrCoreVersionChecker.java",
+  "java/src/org/chromium/chrome/browser/vr/VrDaydreamApi.java",
+  "java/src/org/chromium/chrome/browser/vr/VrDelegateImpl.java",
+  "java/src/org/chromium/chrome/browser/vr/VrDelegateProviderImpl.java",
+  "java/src/org/chromium/chrome/browser/vr/VrDialog.java",
+  "java/src/org/chromium/chrome/browser/vr/VrDialogManager.java",
+  "java/src/org/chromium/chrome/browser/vr/VrFeedbackStatus.java",
+  "java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java",
+  "java/src/org/chromium/chrome/browser/vr/VrInputConnection.java",
+  "java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java",
+  "java/src/org/chromium/chrome/browser/vr/VrModalPresenter.java",
+  "java/src/org/chromium/chrome/browser/vr/VrPopupWindow.java",
+  "java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java",
+  "java/src/org/chromium/chrome/browser/vr/VrShell.java",
+  "java/src/org/chromium/chrome/browser/vr/VrToast.java",
+  "java/src/org/chromium/chrome/browser/vr/VrToastManager.java",
+  "java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java",
+  "java/src/org/chromium/chrome/browser/vr/VrViewContainer.java",
+  "java/src/org/chromium/chrome/browser/vr/VrWindowAndroid.java",
+]
+
 chrome_test_java_sources = [
   "javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java",
   "javatests/src/org/chromium/chrome/browser/AudioTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
index 312eb6837..a24bd02 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -127,6 +127,31 @@
 
     @Test
     @SmallTest
+    public void testAccessorySheetHiddenWhenRefocusingField()
+            throws InterruptedException, TimeoutException {
+        mHelper.loadTestPage(false);
+        mHelper.createTestTab();
+
+        // Focus the field to bring up the accessory.
+        mHelper.clickPasswordField();
+        mHelper.waitForKeyboard();
+
+        // Check that ONLY the accessory is there but the sheet is still hidden.
+        whenDisplayed(withId(R.id.keyboard_accessory));
+        onView(withId(R.id.keyboard_accessory_sheet)).check(doesNotExist());
+
+        // Trigger the sheet and wait for it to open and the keyboard to disappear.
+        onView(withId(R.id.tabs)).perform(selectTabAtPosition(0));
+        mHelper.waitForKeyboardToDisappear();
+        whenDisplayed(withId(R.id.keyboard_accessory_sheet));
+
+        mHelper.clickPasswordField();
+        mHelper.waitForKeyboard();
+        mHelper.waitToBeHidden(withId(R.id.keyboard_accessory_sheet));
+    }
+
+    @Test
+    @SmallTest
     public void testHidingSheetBringsBackKeyboard() throws InterruptedException, TimeoutException {
         mHelper.loadTestPage(false);
         mHelper.createTestTab();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index c605f388..1e755d9e 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-70.0.3510.3_rc-r1.afdo.bz2
+chromeos-chrome-amd64-70.0.3517.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index dc22933..279f50c 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -6,6 +6,7 @@
 import("//chrome/common/features.gni")
 import("//chromeos/assistant/assistant.gni")
 import("//components/nacl/features.gni")
+import("//device/vr/buildflags/buildflags.gni")
 import("//ppapi/buildflags/buildflags.gni")
 import("//printing/buildflags/buildflags.gni")
 import("//services/catalog/public/tools/catalog.gni")
@@ -436,6 +437,11 @@
       "//chrome/services/wifi_util_win:manifest",
     ]
   }
+
+  if (enable_isolated_xr_service) {
+    packaged_services += [ "//chrome/services/isolated_xr_device:manifest" ]
+  }
+
   if (is_android) {
     packaged_services += [ ":chrome_download_manager_manifest" ]
   } else {
diff --git a/chrome/app/vector_icons/picture_in_picture_control_background.icon b/chrome/app/vector_icons/picture_in_picture_control_background.icon
index b243eb24..cf4d0c5 100644
--- a/chrome/app/vector_icons/picture_in_picture_control_background.icon
+++ b/chrome/app/vector_icons/picture_in_picture_control_background.icon
@@ -2,12 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 24,
-MOVE_TO, 12, 2,
-CUBIC_TO, 6.48f, 2, 2, 6.48f, 2, 12,
-R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
-R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
-CUBIC_TO_SHORTHAND, 17.52f, 2, 12, 2,
-CLOSE,
-R_MOVE_TO, -1,
-CLOSE
\ No newline at end of file
+CANVAS_DIMENSIONS, 16,
+CIRCLE, 8, 8, 8
\ No newline at end of file
diff --git a/chrome/app/vr_strings.grdp b/chrome/app/vr_strings.grdp
index 55907e3..6e47881 100644
--- a/chrome/app/vr_strings.grdp
+++ b/chrome/app/vr_strings.grdp
@@ -6,6 +6,10 @@
     Press App button to exit
   </message>
 
+  <message name="IDS_ISOLATED_XR_PROCESS_NAME" desc="The name of the utility process used for XR compositing.">
+    XR Isolated Device Service
+  </message>
+
   <!-- Powerful feature use and permission indicators. -->
   <message name="IDS_VR_SHELL_SITE_IS_TRACKING_LOCATION" desc="Text displayed in a transient bubble to inform the user that the page is tracking location.">
     Site is tracking your location
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 569af2c..995dff3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4293,6 +4293,10 @@
     deps += [ "//chrome/browser/vr:vr_common" ]
   }
 
+  if (enable_isolated_xr_service) {
+    deps += [ "//device/vr/public/mojom" ]
+  }
+
   if (enable_wayland_server) {
     deps += [
       "//components/exo",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 12f65817..05207e8 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -29,6 +29,7 @@
   "+device/gamepad/public/cpp",
   "+device/usb",
   "+device/vr/buildflags/buildflags.h",
+  "+device/vr/public",
   "+extensions/browser",
   "+extensions/common",
   "+extensions/components/javascript_dialog_extensions_client",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 12e5e71..15560b2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4220,6 +4220,13 @@
      flag_descriptions::kSyncStandaloneTransportDescription, kOsAll,
      FEATURE_VALUE_TYPE(switches::kSyncStandaloneTransport)},
 
+#if defined(OS_CHROMEOS)
+    {"enable-chromevox-developer-option",
+     flag_descriptions::kEnableChromevoxDeveloperOptionName,
+     flag_descriptions::kEnableChromevoxDeveloperOptionDescription, kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnableChromevoxDeveloperOption)},
+#endif
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/metrics/BUILD.gn b/chrome/browser/android/metrics/BUILD.gn
index af1cf686e..2180062 100644
--- a/chrome/browser/android/metrics/BUILD.gn
+++ b/chrome/browser/android/metrics/BUILD.gn
@@ -13,6 +13,8 @@
     deps = [
       "//chrome/browser:browser",
       "//chrome/browser/android/metrics:jni_headers",
+      "//components/metrics_services_manager:metrics_services_manager",
+      "//components/ukm:ukm",
     ]
   }
 
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn
index 3d80b3b..2856e3b2 100644
--- a/chrome/browser/android/vr/BUILD.gn
+++ b/chrome/browser/android/vr/BUILD.gn
@@ -31,7 +31,6 @@
     "mailbox_to_surface_bridge.h",
     "metrics_util_android.cc",
     "metrics_util_android.h",
-    "register_jni.h",
     "scoped_gpu_trace.cc",
     "scoped_gpu_trace.h",
     "vr_controller.cc",
@@ -42,7 +41,6 @@
     "vr_gl_thread.h",
     "vr_input_connection.cc",
     "vr_input_connection.h",
-    "vr_module_provider.cc",
     "vr_shell.cc",
     "vr_shell.h",
     "vr_shell_delegate.cc",
@@ -129,66 +127,12 @@
   }
 }
 
-android_library("java") {
-  java_files = [
-    "//chrome/android/java/src/org/chromium/chrome/browser/component_updater/VrAssetsComponentInstaller.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/AndroidUiGestureTarget.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/EmptySniffingVrViewContainer.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/BuildConstants.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/TextEditAction.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/VrInputMethodManagerWrapper.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/NoopCanvas.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/OnDispatchTouchEventCallback.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrCancelAnimationActivity.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrCompositorSurfaceManager.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrCoreInfo.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrCoreVersionChecker.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrDaydreamApi.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrDelegateImpl.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrDelegateProviderImpl.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrDialog.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrDialogManager.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrFeedbackStatus.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrInputConnection.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrModalPresenter.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrPopupWindow.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrToast.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrToastManager.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrViewContainer.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrWindowAndroid.java",
-  ]
-
-  classpath_deps = [
-    "//base:base_java",
-    "//chrome/android:chrome_java",
-    "//components/policy/android:policy_java",
-    "//content/public/android:content_java",
-    "//third_party/android_tools:android_arch_lifecycle_common_java",
-    "//third_party/android_tools:android_arch_lifecycle_runtime_java",
-    "//third_party/android_tools:android_support_annotations_java",
-    "//third_party/android_tools:android_support_v7_appcompat_java",
-    "//third_party/gvr-android-keyboard:kb_java",
-    "//third_party/gvr-android-sdk:gvr_common_java",
-    "//ui/android:ui_full_java",
-    "//ui/android:ui_utils_java",
-  ]
-}
-
 generate_jni("vr_jni_headers") {
   sources = [
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/AndroidUiGestureTarget.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrCoreInfo.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrInputConnection.java",
-    "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java",
     "//chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java",
@@ -205,11 +149,3 @@
     jni_package = "vr"
   }
 }
-
-if (current_toolchain == default_toolchain) {
-  generate_jni_registration("jni_registration") {
-    target = ":java"
-    output = "$target_gen_dir/${target_name}.h"
-    namespace = "vr"
-  }
-}
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.cc b/chrome/browser/android/vr/arcore_device/arcore_device.cc
index e03b990..46e5139 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device.cc
@@ -34,9 +34,9 @@
 
 namespace {
 
-mojom::VRDisplayInfoPtr CreateVRDisplayInfo(uint32_t device_id) {
+mojom::VRDisplayInfoPtr CreateVRDisplayInfo(mojom::XRDeviceId device_id) {
   mojom::VRDisplayInfoPtr device = mojom::VRDisplayInfo::New();
-  device->index = device_id;
+  device->id = device_id;
   device->displayName = "ARCore VR Device";
   device->capabilities = mojom::VRDisplayCapabilities::New();
   device->capabilities->hasPosition = true;
@@ -68,7 +68,7 @@
 }  // namespace
 
 ARCoreDevice::ARCoreDevice()
-    : VRDeviceBase(VRDeviceId::ARCORE_DEVICE_ID),
+    : VRDeviceBase(mojom::XRDeviceId::ARCORE_DEVICE_ID),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       mailbox_bridge_(std::make_unique<vr::MailboxToSurfaceBridge>()),
       weak_ptr_factory_(this) {
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc
index fe9666fa6..51a4e428 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc
@@ -13,10 +13,10 @@
 ARCoreDeviceProvider::~ARCoreDeviceProvider() = default;
 
 void ARCoreDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
     base::OnceClosure initialization_complete) {
   arcore_device_ = base::WrapUnique(new ARCoreDevice());
   add_device_callback.Run(arcore_device_->GetId(),
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_provider.h b/chrome/browser/android/vr/arcore_device/arcore_device_provider.h
index 48317db..47e1f00 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device_provider.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_device_provider.h
@@ -19,10 +19,10 @@
   ARCoreDeviceProvider();
   ~ARCoreDeviceProvider() override;
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
       base::OnceClosure initialization_complete) override;
   bool Initialized() override;
 
diff --git a/chrome/browser/android/vr/register_jni.cc b/chrome/browser/android/vr/register_jni.cc
deleted file mode 100644
index c1e87c5..0000000
--- a/chrome/browser/android/vr/register_jni.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/vr/register_jni.h"
-
-#include "base/android/jni_utils.h"
-#include "chrome/browser/android/vr/jni_registration.h"
-
-namespace vr {
-
-bool RegisterJni(JNIEnv* env) {
-  if (!base::android::IsSelectiveJniRegistrationEnabled(env) &&
-      !vr::RegisterNonMainDexNatives(env)) {
-    return false;
-  }
-  if (!vr::RegisterMainDexNatives(env)) {
-    return false;
-  }
-  return true;
-}
-
-}  // namespace vr
diff --git a/chrome/browser/android/vr/register_jni.h b/chrome/browser/android/vr/register_jni.h
deleted file mode 100644
index 63fa103..0000000
--- a/chrome/browser/android/vr/register_jni.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_VR_REGISTER_JNI_H_
-#define CHROME_BROWSER_ANDROID_VR_REGISTER_JNI_H_
-
-#include <jni.h>
-
-namespace vr {
-
-bool RegisterJni(JNIEnv* env);
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_ANDROID_VR_REGISTER_JNI_H_
diff --git a/chrome/browser/android/vr/register_jni_monochrome.cc b/chrome/browser/android/vr/register_jni_monochrome.cc
deleted file mode 100644
index 24834a9..0000000
--- a/chrome/browser/android/vr/register_jni_monochrome.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/vr/register_jni.h"
-
-namespace vr {
-
-bool RegisterJni(JNIEnv* env) {
-  return true;
-}
-
-}  // namespace vr
diff --git a/chrome/browser/android/vr/vr_module_provider.cc b/chrome/browser/android/vr/vr_module_provider.cc
deleted file mode 100644
index 15e49ba..0000000
--- a/chrome/browser/android/vr/vr_module_provider.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/vr/register_jni.h"
-#include "jni/VrModuleProvider_jni.h"
-
-namespace vr {
-
-static void JNI_VrModuleProvider_RegisterJni(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jclass>& clazz) {
-  CHECK(RegisterJni(env));
-}
-
-}  // namespace vr
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc
index 6057159e..c6c75e9 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -271,7 +271,7 @@
          VrSupportLevel::kVrNeedsUpdate;
 }
 
-void VrShellDelegate::SetDeviceId(unsigned int device_id) {
+void VrShellDelegate::SetDeviceId(device::mojom::XRDeviceId device_id) {
   device_id_ = device_id;
   if (vr_shell_) {
     device::GvrDevice* device = GetDevice();
diff --git a/chrome/browser/android/vr/vr_shell_delegate.h b/chrome/browser/android/vr/vr_shell_delegate.h
index 5f025ae..0d9e60d8 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.h
+++ b/chrome/browser/android/vr/vr_shell_delegate.h
@@ -76,7 +76,7 @@
  private:
   // device::GvrDelegateProvider implementation.
   bool ShouldDisableGvrDevice() override;
-  void SetDeviceId(unsigned int device_id) override;
+  void SetDeviceId(device::mojom::XRDeviceId device_id) override;
   void StartWebXRPresentation(
       device::mojom::VRDisplayInfoPtr display_info,
       device::mojom::XRRuntimeSessionOptionsPtr options,
@@ -94,7 +94,8 @@
   std::unique_ptr<VrCoreInfo> MakeVrCoreInfo(JNIEnv* env);
 
   base::android::ScopedJavaGlobalRef<jobject> j_vr_shell_delegate_;
-  unsigned int device_id_ = 0;
+  device::mojom::XRDeviceId device_id_ =
+      device::mojom::XRDeviceId::GVR_DEVICE_ID;
   VrShell* vr_shell_ = nullptr;
 
   // Deferred callback stored for later use in cases where vr_shell
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 5a8030a9..3d8e362 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -40,7 +40,6 @@
 class WebRtcLogUploader;
 
 namespace network {
-class NetworkConnectionTracker;
 class NetworkQualityTracker;
 class SharedURLLoaderFactory;
 }
@@ -183,10 +182,6 @@
   // backed by the IOThread's URLRequestContext.
   virtual SystemNetworkContextManager* system_network_context_manager() = 0;
 
-  // Returns a NetworkConnectionTracker that can be used to subscribe for
-  // network change events.
-  virtual network::NetworkConnectionTracker* network_connection_tracker() = 0;
-
   // Returns a NetworkQualityTracker that can be used to subscribe for
   // network quality change events.
   virtual network::NetworkQualityTracker* network_quality_tracker() = 0;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 94d19844..cca59ea3d 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -134,7 +134,6 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/network_quality_tracker.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "services/preferences/public/cpp/in_process_service_factory.h"
@@ -632,18 +631,6 @@
   return system_network_context_manager()->GetSharedURLLoaderFactory();
 }
 
-network::NetworkConnectionTracker*
-BrowserProcessImpl::network_connection_tracker() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(io_thread_);
-  if (!network_connection_tracker_) {
-    network_connection_tracker_ =
-        std::make_unique<network::NetworkConnectionTracker>(
-            base::BindRepeating(&content::GetNetworkService));
-  }
-  return network_connection_tracker_.get();
-}
-
 network::NetworkQualityTracker* BrowserProcessImpl::network_quality_tracker() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(io_thread_);
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index ecd6a24..89ebadfe 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -123,7 +123,6 @@
   SystemNetworkContextManager* system_network_context_manager() override;
   scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory()
       override;
-  network::NetworkConnectionTracker* network_connection_tracker() override;
   network::NetworkQualityTracker* network_quality_tracker() override;
   WatchDogThread* watchdog_thread() override;
   ProfileManager* profile_manager() override;
@@ -240,9 +239,6 @@
 
   std::unique_ptr<SystemNetworkContextManager> system_network_context_manager_;
 
-  std::unique_ptr<network::NetworkConnectionTracker>
-      network_connection_tracker_;
-
   std::unique_ptr<network::NetworkQualityTracker> network_quality_tracker_;
 
   bool created_icon_manager_ = false;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0458d3db..f34402e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -211,6 +211,7 @@
 #include "components/translate/core/common/translate_switches.h"
 #include "components/url_formatter/url_fixer.h"
 #include "components/variations/variations_associated_data.h"
+#include "components/variations/variations_http_header_provider.h"
 #include "components/variations/variations_switches.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_child_process_host.h"
@@ -250,6 +251,7 @@
 #include "content/public/common/web_preferences.h"
 #include "device/usb/public/mojom/chooser_service.mojom.h"
 #include "device/usb/public/mojom/device_manager.mojom.h"
+#include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/google_api_keys.h"
@@ -515,6 +517,10 @@
 #include "services/content/simple_browser/public/mojom/constants.mojom.h"
 #endif
 
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#endif
+
 using base::FileDescriptor;
 using content::BrowserThread;
 using content::BrowserURLHandler;
@@ -3626,6 +3632,11 @@
 
 void ChromeContentBrowserClient::RegisterOutOfProcessServices(
     OutOfProcessServiceMap* services) {
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+  (*services)[device::mojom::kVrIsolatedServiceName] = base::BindRepeating(
+      &l10n_util::GetStringUTF16, IDS_ISOLATED_XR_PROCESS_NAME);
+#endif
+
 #if BUILDFLAG(ENABLE_PRINTING)
   (*services)[printing::mojom::kServiceName] =
       base::BindRepeating(&l10n_util::GetStringUTF16,
@@ -4229,11 +4240,14 @@
         !is_off_the_record &&
         !io_data->google_services_account_id()->GetValue().empty();
 
+    std::string variation_ids_header =
+        variations::VariationsHttpHeaderProvider::GetInstance()
+            ->GetClientDataHeader(is_signed_in);
+
     result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
-        is_off_the_record, is_signed_in,
-        io_data->force_google_safesearch()->GetValue(),
+        is_off_the_record, io_data->force_google_safesearch()->GetValue(),
         io_data->force_youtube_restrict()->GetValue(),
-        io_data->allowed_domains_for_apps()->GetValue()));
+        io_data->allowed_domains_for_apps()->GetValue(), variation_ids_header));
   }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index a4b7c78..b1a077cc 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -72,7 +72,8 @@
         ],
         "unzip": [ "unzip_file" ],
         "util_win" : [ "shell_util_win" ],
-        "wifi_util_win": [ "wifi_credentials" ]
+        "wifi_util_win": [ "wifi_credentials" ],
+        "xr_device_service": [ "xr_device_provider" ]
       }
     },
     "navigation:frame": {
diff --git a/chrome/browser/chrome_do_not_track_browsertest.cc b/chrome/browser/chrome_do_not_track_browsertest.cc
index 694e3ad..a1f355a0 100644
--- a/chrome/browser/chrome_do_not_track_browsertest.cc
+++ b/chrome/browser/chrome_do_not_track_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -31,6 +33,10 @@
         &text));
     EXPECT_EQ(expected_content, text);
   }
+
+  content::WebContents* GetWebContents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(ChromeDoNotTrackTest, NotEnabled) {
@@ -39,11 +45,8 @@
 
   GURL url = embedded_test_server()->GetURL("/echoheader?DNT");
   ui_test_utils::NavigateToURL(browser(), url);
-  EXPECT_EQ(false, browser()
-                       ->tab_strip_model()
-                       ->GetActiveWebContents()
-                       ->GetMutableRendererPrefs()
-                       ->enable_do_not_track);
+  EXPECT_EQ(false,
+            GetWebContents()->GetMutableRendererPrefs()->enable_do_not_track);
   ExpectPageTextEq("None");
 }
 
@@ -53,12 +56,120 @@
 
   GURL url = embedded_test_server()->GetURL("/echoheader?DNT");
   ui_test_utils::NavigateToURL(browser(), url);
-  EXPECT_EQ(true, browser()
-                      ->tab_strip_model()
-                      ->GetActiveWebContents()
-                      ->GetMutableRendererPrefs()
-                      ->enable_do_not_track);
+  EXPECT_EQ(true,
+            GetWebContents()->GetMutableRendererPrefs()->enable_do_not_track);
   ExpectPageTextEq("1");
 }
 
+// Checks that the DNT header is preserved when fetching from a dedicated
+// worker.
+IN_PROC_BROWSER_TEST_F(ChromeDoNotTrackTest, FetchFromWorker) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  SetEnableDoNotTrack(true /* enabled */);
+
+  const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
+  const GURL url = embedded_test_server()->GetURL(
+      std::string("/workers/fetch_from_worker.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  const std::string script = "fetch_from_worker('" + fetch_url.spec() + "');";
+  ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  const base::string16 title = base::ASCIIToUTF16("DONE");
+  {
+    content::TitleWatcher watcher(GetWebContents(), title);
+    EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  }
+  ExpectPageTextEq("1");
+
+  // Updating settings should be reflected immediately.
+  // Disabled due to crbug.com/853085.
+  //
+  // SetEnableDoNotTrack(false /* enabled */);
+  // ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  // {
+  //   content::TitleWatcher watcher(GetWebContents(), title);
+  //   EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  // }
+  // ExpectPageTextEq("None");
+}
+
+// Checks that the DNT header is preserved when fetching from a shared worker.
+//
+// Disabled on Android since a shared worker is not available on Android:
+// crbug.com/869745.
+#if defined(OS_ANDROID)
+#define MAYBE_FetchFromSharedWorker DISABLED_FetchFromSharedWorker
+#else
+#define MAYBE_FetchFromSharedWorker FetchFromSharedWorker
+#endif
+IN_PROC_BROWSER_TEST_F(ChromeDoNotTrackTest, MAYBE_FetchFromSharedWorker) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  SetEnableDoNotTrack(true /* enabled */);
+
+  const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
+  const GURL url = embedded_test_server()->GetURL(
+      std::string("/workers/fetch_from_shared_worker.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  const std::string script =
+      "fetch_from_shared_worker('" + fetch_url.spec() + "');";
+  ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  const base::string16 title = base::ASCIIToUTF16("DONE");
+  {
+    content::TitleWatcher watcher(GetWebContents(), title);
+    EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  }
+  ExpectPageTextEq("1");
+
+  // Updating settings should be reflected immediately.
+  // Disabled due to crbug.com/853085.
+  //
+  // SetEnableDoNotTrack(false /* enabled */);
+  // ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  // {
+  //   content::TitleWatcher watcher(GetWebContents(), title);
+  //   EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  // }
+  // ExpectPageTextEq("None");
+}
+
+// Checks that the DNT header is preserved when fetching from a service worker.
+IN_PROC_BROWSER_TEST_F(ChromeDoNotTrackTest, FetchFromServiceWorker) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  SetEnableDoNotTrack(true /* enabled */);
+
+  const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
+  const GURL url = embedded_test_server()->GetURL(
+      std::string("/workers/fetch_from_service_worker.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Wait until service worker become ready.
+  const base::string16 title = base::ASCIIToUTF16("DONE");
+  {
+    content::TitleWatcher watcher(GetWebContents(), title);
+    EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  }
+  ExpectPageTextEq("ready");
+
+  const std::string script =
+      "fetch_from_service_worker('" + fetch_url.spec() + "');";
+  ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  {
+    content::TitleWatcher watcher(GetWebContents(), title);
+    EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  }
+  ExpectPageTextEq("1");
+
+  // Updating settings should be reflected immediately.
+  // Disabled due to crbug.com/853085.
+  //
+  // SetEnableDoNotTrack(false /* enabled */);
+  // ASSERT_TRUE(ExecJs(GetWebContents(), script));
+  // {
+  //   content::TitleWatcher watcher(GetWebContents(), title);
+  //   EXPECT_EQ(title, watcher.WaitAndGetTitle());
+  // }
+  // ExpectPageTextEq("None");
+}
+
 }  // namespace
diff --git a/chrome/browser/chromeos/arc/intent_helper/open_with_menu.cc b/chrome/browser/chromeos/arc/intent_helper/open_with_menu.cc
index 2141168..32255b31 100644
--- a/chrome/browser/chromeos/arc/intent_helper/open_with_menu.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/open_with_menu.cc
@@ -14,6 +14,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/renderer_context_menu/render_view_context_menu_proxy.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/common/context_menu_params.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -45,6 +46,10 @@
 OpenWithMenu::~OpenWithMenu() = default;
 
 void OpenWithMenu::InitMenu(const content::ContextMenuParams& params) {
+  // Enforcing no items are added to the context menu during incognito mode.
+  if (context_->IsOffTheRecord())
+    return;
+
   menu_model_ = LinkHandlerModel::Create(context_, params.link_url);
   if (!menu_model_)
     return;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 969e670..164ef66 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -532,6 +532,8 @@
 void CrostiniManager::MaybeUpgradeCrostiniAfterTerminaCheck(
     bool is_registered) {
   is_cros_termina_registered_ = is_registered;
+  VLOG(1) << "cros-termina is "
+          << (is_registered ? "registered" : "not registered");
   if (!is_cros_termina_registered_) {
     return;
   }
@@ -606,7 +608,9 @@
   bool is_successful =
       error == component_updater::CrOSComponentManager::Error::NONE;
 
-  if (!is_successful) {
+  if (is_successful) {
+    is_cros_termina_registered_ = true;
+  } else {
     LOG(ERROR)
         << "Failed to install the cros-termina component with error code: "
         << static_cast<int>(error);
diff --git a/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc b/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
index 99368eb..407d889 100644
--- a/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
@@ -17,6 +17,7 @@
 #include "components/arc/arc_util.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_app_instance.h"
+#include "extensions/common/switches.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
 
@@ -45,6 +46,10 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     extensions::ExtensionApiTest::SetUpCommandLine(command_line);
     arc::SetArcAvailableCommandLineForTesting(command_line);
+    // Whitelist the test platform app.
+    command_line->AppendSwitchASCII(
+        extensions::switches::kWhitelistedExtensionID,
+        "fgkfegllpjfhppblcabhjjipnfelohej");
   }
 
   void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index f4baac8..191c0ec 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -245,14 +245,8 @@
                       TestCase("createFolderDrive"),
                       TestCase("createFolderDrive").EnableDriveFs()));
 
-// crbug.com/871684
-#if !defined(NDEBUG)
-#define MAYBE_KeyboardOperations DISABLED_KeyboardOperations
-#else
-#define MAYBE_KeyboardOperations KeyboardOperations
-#endif
 WRAPPED_INSTANTIATE_TEST_CASE_P(
-    MAYBE_KeyboardOperations, /* keyboard_operations.js */
+    KeyboardOperations, /* keyboard_operations.js */
     FilesAppBrowserTest,
     ::testing::Values(TestCase("keyboardDeleteDownloads").InGuestMode(),
                       TestCase("keyboardDeleteDownloads"),
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
index 6702e88..62840e6 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/file_manager/file_manager_jstest_base.h"
 
-#include <vector>
 #include "base/path_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -19,16 +18,31 @@
 void FileManagerJsTestBase::RunTest(const base::FilePath& file) {
   base::FilePath root_path;
   ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path));
+  base::FilePath full_path = root_path.Append(base_path_).Append(file);
+  ASSERT_TRUE(base::PathExists(full_path)) << full_path.value();
+  RunTestImpl(net::FilePathToFileURL(full_path));
+}
 
-  const GURL url = net::FilePathToFileURL(
-      root_path.Append(base_path_)
-      .Append(file));
+void FileManagerJsTestBase::RunGeneratedTest(const std::string& file) {
+  base::FilePath path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &path));
+  path = path.AppendASCII("gen");
+
+  // Serve the generated html file from out/gen. It references files from
+  // DIR_SOURCE_ROOT, so serve from there as well. An alternative would be to
+  // copy the js files as a build step and serve file:// URLs, but the embedded
+  // test server gives better output for troubleshooting errors.
+  embedded_test_server()->ServeFilesFromDirectory(path.Append(base_path_));
+  embedded_test_server()->ServeFilesFromSourceDirectory(base::FilePath());
+
+  ASSERT_TRUE(embedded_test_server()->Start());
+  RunTestImpl(embedded_test_server()->GetURL(file));
+}
+
+void FileManagerJsTestBase::RunTestImpl(const GURL& url) {
   ui_test_utils::NavigateToURL(browser(), url);
-
   content::WebContents* const web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
-
-  const std::vector<int> empty_libraries;
-  EXPECT_TRUE(ExecuteWebUIResourceTest(web_contents, empty_libraries));
+  EXPECT_TRUE(ExecuteWebUIResourceTest(web_contents, {}));
 }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.h b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.h
index 7095cf26..80faa2c86 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest_base.h
@@ -15,7 +15,13 @@
   // Runs all test functions in |file|, waiting for them to complete.
   void RunTest(const base::FilePath& file);
 
+  // Same as RunTest, but starts the EmbeddedTestServer to serve a generated
+  // |file|, relative to DIR_EXE/gen/base_path.
+  void RunGeneratedTest(const std::string& file);
+
  private:
+  void RunTestImpl(const GURL& url);
+
   base::FilePath base_path_;
 };
 
diff --git a/chrome/browser/chromeos/file_manager/gallery_jstest.cc b/chrome/browser/chromeos/file_manager/gallery_jstest.cc
index 375abe1..3c9b71a 100644
--- a/chrome/browser/chromeos/file_manager/gallery_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_jstest.cc
@@ -6,13 +6,13 @@
 
 class GalleryJsTest : public FileManagerJsTestBase {
  protected:
-  GalleryJsTest() : FileManagerJsTestBase(
-      base::FilePath(FILE_PATH_LITERAL("ui/file_manager/gallery/js"))) {}
+  GalleryJsTest()
+      : FileManagerJsTestBase(
+            base::FilePath(FILE_PATH_LITERAL("ui/file_manager/gallery/js"))) {}
 };
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, ImageEncoderTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("image_editor/image_encoder_unittest.html")));
+  RunGeneratedTest("/image_editor/image_encoder_unittest.html");
 }
 
 // Disabled on ASan builds due to a consistent failure. https://crbug.com/762831
@@ -22,33 +22,29 @@
 #define MAYBE_ExifEncoderTest ExifEncoderTest
 #endif
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, MAYBE_ExifEncoderTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("image_editor/exif_encoder_unittest.html")));
+  RunGeneratedTest("/image_editor/exif_encoder_unittest.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, ImageViewTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("image_editor/image_view_unittest.html")));
+  RunGeneratedTest("/image_editor/image_view_unittest.html");
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, EntryListWatcherTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("entry_list_watcher_unittest.html")));
+  RunTest(
+      base::FilePath(FILE_PATH_LITERAL("entry_list_watcher_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryUtilTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("gallery_util_unittest.html")));
+  RunTest(base::FilePath(FILE_PATH_LITERAL("gallery_util_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryItemTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("gallery_item_unittest.html")));
+  RunTest(base::FilePath(FILE_PATH_LITERAL("gallery_item_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, GalleryDataModelTest) {
-  RunTest(base::FilePath(
-      FILE_PATH_LITERAL("gallery_data_model_unittest.html")));
+  RunTest(
+      base::FilePath(FILE_PATH_LITERAL("gallery_data_model_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryJsTest, RibbonTest) {
diff --git a/chrome/browser/chromeos/logging.cc b/chrome/browser/chromeos/logging.cc
index edd99c39..e5b4260 100644
--- a/chrome/browser/chromeos/logging.cc
+++ b/chrome/browser/chromeos/logging.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/sys_info.h"
 #include "base/task/post_task.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/logging_chrome.h"
@@ -46,6 +47,11 @@
 void RedirectChromeLogging(const base::CommandLine& command_line) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  // Only redirect when on an actual device. To do otherwise conflicts with
+  // --vmodule that developers may want to use.
+  if (!base::SysInfo::IsRunningOnChromeOS())
+    return;
+
   if (chrome_logging_redirected_) {
     // TODO: Support multiple active users. http://crbug.com/230345
     LOG(WARNING) << "NOT redirecting logging for multi-profiles case.";
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index a19791f..ce6f9929 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service_factory.h"
 #include "chrome/browser/chromeos/child_accounts/screen_time_controller_factory.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
@@ -142,6 +143,8 @@
       policy::AppInstallEventLogManagerWrapper::CreateForProfile(user_profile);
     }
     arc::ArcServiceLauncher::Get()->OnPrimaryUserProfilePrepared(user_profile);
+    crostini::CrostiniManager::GetInstance()->MaybeUpgradeCrostini(
+        user_profile);
 
     if (user->GetType() == user_manager::USER_TYPE_CHILD) {
       ScreenTimeControllerFactory::GetForBrowserContext(user_profile);
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 98c95274..203617b 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1070,8 +1070,7 @@
 
 void UserSessionManager::PreStartSession() {
   // Switch log file as soon as possible.
-  if (base::SysInfo::IsRunningOnChromeOS())
-    logging::RedirectChromeLogging(*base::CommandLine::ForCurrentProcess());
+  logging::RedirectChromeLogging(*base::CommandLine::ForCurrentProcess());
 }
 
 void UserSessionManager::StoreUserContextDataBeforeProfileIsCreated() {
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 4d01e5b..f4de75c6 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -775,7 +775,9 @@
 
   std::string owner_email;
   cros_settings_->GetString(kDeviceOwner, &owner_email);
-  SetOwnerId(AccountId::FromUserEmail(owner_email));
+  const AccountId owner_account_id = user_manager::known_user::GetAccountId(
+      owner_email, std::string() /* id */, AccountType::UNKNOWN);
+  SetOwnerId(owner_account_id);
 
   EnsureUsersLoaded();
 
diff --git a/chrome/browser/chromeos/policy/app_install_event_log_collector.cc b/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
index 7b00403..cb3e693 100644
--- a/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
@@ -16,6 +16,7 @@
 #include "chromeos/network/network_type_pattern.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/network_service_instance.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace em = enterprise_management;
@@ -65,8 +66,7 @@
       pending_packages_(pending_packages) {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
       this);
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
   // Might not be available in unit test.
   arc::ArcPolicyBridge* const policy_bridge =
       arc::ArcPolicyBridge::GetForBrowserContext(profile_);
@@ -86,8 +86,7 @@
   }
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
       this);
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
   arc::ArcPolicyBridge* const policy_bridge =
       arc::ArcPolicyBridge::GetForBrowserContext(profile_);
   if (policy_bridge) {
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
index 3bd6673..5724ac4 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
@@ -14,7 +14,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/server_backed_device_state.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/pref_names.h"
@@ -24,6 +23,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "crypto/sha2.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
@@ -376,8 +376,7 @@
 }
 
 AutoEnrollmentClientImpl::~AutoEnrollmentClientImpl() {
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 // static
@@ -388,10 +387,8 @@
 
 void AutoEnrollmentClientImpl::Start() {
   // (Re-)register the network change observer.
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 
   // Drop the previous job and reset state.
   request_job_.reset();
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index da1f5895..ae08692 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -241,7 +241,9 @@
   // Default is to enable smart dim, unless user profile specifically says
   // otherwise.
   bool smart_dim_enabled = true;
-  const Profile* const profile = ProfileManager::GetActiveUserProfile();
+  // If there are multiple users, the primary one may have more-restrictive
+  // policy-controlled settings.
+  const Profile* const profile = ProfileManager::GetPrimaryUserProfile();
   if (profile) {
     smart_dim_enabled =
         profile->GetPrefs()->GetBoolean(ash::prefs::kPowerSmartDimEnabled);
diff --git a/chrome/browser/devtools/devtools_auto_opener.cc b/chrome/browser/devtools/devtools_auto_opener.cc
index 834030e3..af0bda1 100644
--- a/chrome/browser/devtools/devtools_auto_opener.cc
+++ b/chrome/browser/devtools/devtools_auto_opener.cc
@@ -15,10 +15,14 @@
 DevToolsAutoOpener::~DevToolsAutoOpener() {
 }
 
-void DevToolsAutoOpener::TabInsertedAt(TabStripModel* tab_strip_model,
-                                       content::WebContents* contents,
-                                       int index,
-                                       bool foreground) {
-  if (!DevToolsWindow::IsDevToolsWindow(contents))
-    DevToolsWindow::OpenDevToolsWindow(contents);
+void DevToolsAutoOpener::OnTabStripModelChanged(
+    const TabStripModelChange& change,
+    const TabStripSelectionChange& selection) {
+  if (change.type() != TabStripModelChange::kInserted)
+    return;
+
+  for (const auto& delta : change.deltas()) {
+    if (!DevToolsWindow::IsDevToolsWindow(delta.insert.contents))
+      DevToolsWindow::OpenDevToolsWindow(delta.insert.contents);
+  }
 }
diff --git a/chrome/browser/devtools/devtools_auto_opener.h b/chrome/browser/devtools/devtools_auto_opener.h
index 7efe2ea7..ae5bb89 100644
--- a/chrome/browser/devtools/devtools_auto_opener.h
+++ b/chrome/browser/devtools/devtools_auto_opener.h
@@ -15,10 +15,9 @@
 
  private:
   // TabStripModelObserver overrides.
-  void TabInsertedAt(TabStripModel* tab_strip_model,
-                     content::WebContents* contents,
-                     int index,
-                     bool foreground) override;
+  void OnTabStripModelChanged(
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override;
 
   BrowserTabStripTracker browser_tab_strip_tracker_;
 
diff --git a/chrome/browser/devtools/global_confirm_info_bar.cc b/chrome/browser/devtools/global_confirm_info_bar.cc
index d283a99..1e1dc7f2 100644
--- a/chrome/browser/devtools/global_confirm_info_bar.cc
+++ b/chrome/browser/devtools/global_confirm_info_bar.cc
@@ -177,11 +177,14 @@
   }
 }
 
-void GlobalConfirmInfoBar::TabInsertedAt(TabStripModel* tab_strip_model,
-                                         content::WebContents* web_contents,
-                                         int index,
-                                         bool foreground) {
-  MaybeAddInfoBar(web_contents);
+void GlobalConfirmInfoBar::OnTabStripModelChanged(
+    const TabStripModelChange& change,
+    const TabStripSelectionChange& selection) {
+  if (change.type() != TabStripModelChange::kInserted)
+    return;
+
+  for (const auto& delta : change.deltas())
+    MaybeAddInfoBar(delta.insert.contents);
 }
 
 void GlobalConfirmInfoBar::TabChangedAt(content::WebContents* web_contents,
diff --git a/chrome/browser/devtools/global_confirm_info_bar.h b/chrome/browser/devtools/global_confirm_info_bar.h
index 7843f26..a91996d3 100644
--- a/chrome/browser/devtools/global_confirm_info_bar.h
+++ b/chrome/browser/devtools/global_confirm_info_bar.h
@@ -43,10 +43,9 @@
   class DelegateProxy;
 
   // TabStripModelObserver:
-  void TabInsertedAt(TabStripModel* tab_strip_model,
-                     content::WebContents* web_contents,
-                     int index,
-                     bool foreground) override;
+  void OnTabStripModelChanged(
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override;
   void TabChangedAt(content::WebContents* web_contents,
                     int index,
                     TabChangeType change_type) override;
diff --git a/chrome/browser/extensions/api/declarative/declarative_apitest.cc b/chrome/browser/extensions/api/declarative/declarative_apitest.cc
index b9f2d90..b82c58c 100644
--- a/chrome/browser/extensions/api/declarative/declarative_apitest.cc
+++ b/chrome/browser/extensions/api/declarative/declarative_apitest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
@@ -186,6 +187,9 @@
   const Extension* extension = InstallExtensionWithUIAutoConfirm(
       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   std::string extension_id(extension->id());
   ASSERT_TRUE(ready.WaitUntilSatisfied());
   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
@@ -260,6 +264,9 @@
   const Extension* extension = InstallExtensionWithUIAutoConfirm(
       ext_dir.Pack(), 1 /*+1 installed extension*/, browser());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   std::string extension_id(extension->id());
   ASSERT_TRUE(ready.WaitUntilSatisfied());
   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
@@ -270,6 +277,9 @@
 
   // 2. Uninstall the extension. Rules are gone and preferences should be empty.
   UninstallExtension(extension_id);
+  // Wait for declarative rules to be removed.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   ui_test_utils::NavigateToURL(browser(), GURL(kArbitraryUrl));
   EXPECT_NE(kTestTitle, GetTitle());
   EXPECT_EQ(0u, NumberOfRegisteredRules(extension_id));
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
index df8b818..792970c 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -361,6 +362,9 @@
   ExtensionTestMessageListener ready("ready", false);
   const Extension* extension = LoadExtension(ext_dir_.UnpackedPath());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   const ExtensionAction* page_action =
       ExtensionActionManager::Get(browser()->profile())
           ->GetPageAction(*extension);
@@ -605,6 +609,9 @@
   ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
   const Extension* extension = LoadExtension(ext_dir_.UnpackedPath());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   const std::string extension_id = extension->id();
   const ExtensionAction* page_action = ExtensionActionManager::Get(
       browser()->profile())->GetPageAction(*extension);
@@ -631,6 +638,9 @@
   EXPECT_EQ(1u, extension_action_test_util::GetTotalPageActionCount(tab));
 
   ReloadExtension(extension_id);  // Invalidates page_action and extension.
+  // Wait for declarative rules to be removed.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   EXPECT_EQ("test_rule",
             ExecuteScriptInBackgroundPage(extension_id, kTestRule));
   // TODO(jyasskin): Apply new rules to existing tabs, without waiting for a
@@ -641,6 +651,9 @@
   EXPECT_EQ(1u, extension_action_test_util::GetTotalPageActionCount(tab));
 
   UnloadExtension(extension_id);
+  // Wait for declarative rules to be removed.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   NavigateInRenderer(tab, GURL("http://test/"));
   EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(0));
   EXPECT_EQ(0u, extension_action_test_util::GetVisiblePageActionCount(tab));
@@ -722,6 +735,9 @@
   scoped_refptr<const Extension> extension =
       loader.LoadExtension(ext_dir_.UnpackedPath());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
 
   const char kScript[] =
       "setRules([{\n"
diff --git a/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc b/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
index 72a79c3..b06f930 100644
--- a/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/version_info/version_info.h"
+#include "content/public/browser/storage_partition.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/test_extension_dir.h"
@@ -74,6 +75,9 @@
   ExtensionTestMessageListener ready("ready", false);
   const Extension* extension = LoadExtension(ext_dir_.UnpackedPath());
   ASSERT_TRUE(extension);
+  // Wait for declarative rules to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
   const ExtensionAction* page_action =
       ExtensionActionManager::Get(browser()->profile())->
       GetPageAction(*extension);
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 68810f8..46d68e7 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -1547,6 +1547,9 @@
       LoadExtension(test_data_dir_.AppendASCII("extension"));
   ASSERT_TRUE(extension);
   EXPECT_TRUE(listener.WaitUntilSatisfied());
+  // Wait for webRequest listeners to be set up.
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->FlushNetworkInterfaceForTesting();
 
   // Have the extension listen for requests to |fake_ntp_script.js|.
   listener.Reply(https_test_server()->GetURL("/fake_ntp_script.js").spec());
diff --git a/chrome/browser/extensions/app_data_migrator_unittest.cc b/chrome/browser/extensions/app_data_migrator_unittest.cc
index 1f804ee..c6c6ecb 100644
--- a/chrome/browser/extensions/app_data_migrator_unittest.cc
+++ b/chrome/browser/extensions/app_data_migrator_unittest.cc
@@ -170,13 +170,12 @@
                                              base::Bind(&DidCreate));
   content::RunAllTasksUntilIdle();
 
-  fs_context->operation_runner()->Write(url_request_context, fs_temp_url,
-                                        blob1.GetBlobDataHandle(), 0,
-                                        base::Bind(&DidWrite));
+  fs_context->operation_runner()->Write(fs_temp_url, blob1.GetBlobDataHandle(),
+                                        0, base::BindRepeating(&DidWrite));
   content::RunAllTasksUntilIdle();
-  fs_context->operation_runner()->Write(url_request_context, fs_persistent_url,
+  fs_context->operation_runner()->Write(fs_persistent_url,
                                         blob1.GetBlobDataHandle(), 0,
-                                        base::Bind(&DidWrite));
+                                        base::BindRepeating(&DidWrite));
   content::RunAllTasksUntilIdle();
 }
 
diff --git a/chrome/browser/extensions/background_xhr_browsertest.cc b/chrome/browser/extensions/background_xhr_browsertest.cc
index 03b32ac..cc98616d 100644
--- a/chrome/browser/extensions/background_xhr_browsertest.cc
+++ b/chrome/browser/extensions/background_xhr_browsertest.cc
@@ -15,7 +15,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
 #include "extensions/browser/browsertest_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
@@ -60,7 +60,8 @@
     GURL test_url = net::AppendQueryParameter(extension->GetResourceURL(path),
                                               "url", url.spec());
     ui_test_utils::NavigateToURL(browser(), test_url);
-    content::FlushNetworkServiceInstanceForTesting();
+    content::BrowserContext::GetDefaultStoragePartition(profile())
+        ->FlushNetworkInterfaceForTesting();
     constexpr char kSendXHRScript[] = R"(
       var xhr = new XMLHttpRequest();
       xhr.open('GET', '%s');
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index 18a69668..6ea2b79 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <cctype>
 #include <string>
 #include <utility>
 
@@ -46,7 +45,6 @@
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/origin_trials/chrome_origin_trial_policy.h"
 #include "chrome/common/url_constants.h"
-#include "chrome/grit/platform_locale_settings.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_service.h"
@@ -61,21 +59,9 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/url_pattern.h"
 #include "net/base/load_flags.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/url_request/url_request.h"
-#include "skia/ext/image_operations.h"
-#include "skia/ext/platform_canvas.h"
 #include "third_party/blink/public/common/manifest/web_display_mode.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_analysis.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/canvas_image_source.h"
-#include "ui/gfx/image/image.h"
 
 #if defined(OS_MACOSX)
 #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.h"
@@ -92,62 +78,6 @@
 
 namespace {
 
-// Overlays a shortcut icon over the bottom left corner of a given image.
-class GeneratedIconImageSource : public gfx::CanvasImageSource {
- public:
-  explicit GeneratedIconImageSource(char letter, SkColor color, int output_size)
-      : gfx::CanvasImageSource(gfx::Size(output_size, output_size), false),
-        letter_(letter),
-        color_(color),
-        output_size_(output_size) {}
-  ~GeneratedIconImageSource() override {}
-
- private:
-  // gfx::CanvasImageSource overrides:
-  void Draw(gfx::Canvas* canvas) override {
-    const uint8_t kLumaThreshold = 190;
-    const int icon_size = output_size_ * 3 / 4;
-    const int icon_inset = output_size_ / 8;
-    const size_t border_radius = output_size_ / 16;
-    const size_t font_size = output_size_ * 7 / 16;
-
-    std::string font_name =
-        l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY);
-#if defined(OS_CHROMEOS)
-    const std::string kChromeOSFontFamily = "Noto Sans";
-    font_name = kChromeOSFontFamily;
-#endif
-
-    // Draw a rounded rect of the given |color|.
-    cc::PaintFlags background_flags;
-    background_flags.setAntiAlias(true);
-    background_flags.setColor(color_);
-
-    gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size);
-    canvas->DrawRoundRect(icon_rect, border_radius, background_flags);
-
-    // The text rect's size needs to be odd to center the text correctly.
-    gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1);
-    // Draw the letter onto the rounded rect. The letter's color depends on the
-    // luma of |color|.
-    const uint8_t luma = color_utils::GetLuma(color_);
-    canvas->DrawStringRectWithFlags(
-        base::string16(1, std::toupper(letter_)),
-        gfx::FontList(gfx::Font(font_name, font_size)),
-        (luma > kLumaThreshold) ? SK_ColorBLACK : SK_ColorWHITE,
-        text_rect,
-        gfx::Canvas::TEXT_ALIGN_CENTER);
-  }
-
-  char letter_;
-
-  SkColor color_;
-
-  int output_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(GeneratedIconImageSource);
-};
-
 std::set<int> SizesToGenerate() {
   // Generate container icons from smaller icons.
   const int kIconSizesToGenerate[] = {
@@ -162,49 +92,8 @@
                        kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
 }
 
-void GenerateIcons(
-    std::set<int> generate_sizes,
-    const GURL& app_url,
-    SkColor generated_icon_color,
-    std::map<int, BookmarkAppHelper::BitmapAndSource>* bitmap_map) {
-  // The letter that will be painted on the generated icon.
-  char icon_letter = ' ';
-  std::string domain_and_registry(
-      net::registry_controlled_domains::GetDomainAndRegistry(
-          app_url,
-          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
-  if (!domain_and_registry.empty()) {
-    icon_letter = domain_and_registry[0];
-  } else if (app_url.has_host()) {
-    icon_letter = app_url.host_piece()[0];
-  }
-
-  // If no color has been specified, use a dark gray so it will stand out on the
-  // black shelf.
-  if (generated_icon_color == SK_ColorTRANSPARENT)
-    generated_icon_color = SK_ColorDKGRAY;
-
-  for (int size : generate_sizes) {
-    BookmarkAppHelper::GenerateIcon(bitmap_map, size, generated_icon_color,
-                                    icon_letter);
-  }
-}
-
-SkBitmap GenerateBitmap(int output_size, SkColor color, char letter) {
-  gfx::ImageSkia icon_image(
-      std::make_unique<GeneratedIconImageSource>(letter, color, output_size),
-      gfx::Size(output_size, output_size));
-  SkBitmap dst;
-  if (dst.tryAllocPixels(icon_image.bitmap()->info())) {
-    icon_image.bitmap()->readPixels(dst.info(), dst.getPixels(), dst.rowBytes(),
-                                    0, 0);
-  }
-  return dst;
-}
-
-void ReplaceWebAppIcons(
-    std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
-    WebApplicationInfo* web_app_info) {
+void ReplaceWebAppIcons(std::map<int, web_app::BitmapAndSource> bitmap_map,
+                        WebApplicationInfo* web_app_info) {
   web_app_info->icons.clear();
 
   // Populate the icon data into the WebApplicationInfo we are using to
@@ -297,7 +186,7 @@
             continue;
 
           downloaded_bitmaps_.push_back(
-              BookmarkAppHelper::BitmapAndSource(url_bitmaps.first, bitmap));
+              web_app::BitmapAndSource(url_bitmaps.first, bitmap));
         }
       }
     }
@@ -319,7 +208,7 @@
     for (const auto& icon : web_app_info_.icons)
       sizes_to_generate.insert(icon.width);
 
-    std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
+    std::map<int, web_app::BitmapAndSource> size_map =
         BookmarkAppHelper::ResizeIconsAndGenerateMissing(
             downloaded_bitmaps_, sizes_to_generate, &web_app_info_);
     BookmarkAppHelper::UpdateWebAppIconsWithoutChangingLinks(size_map,
@@ -335,7 +224,7 @@
   std::unique_ptr<content::WebContents> web_contents_;
   std::unique_ptr<WebAppIconDownloader> web_app_icon_downloader_;
   std::vector<GURL> urls_to_download_;
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded_bitmaps_;
+  std::vector<web_app::BitmapAndSource> downloaded_bitmaps_;
 };
 
 }  // namespace
@@ -383,54 +272,6 @@
 }
 
 // static
-std::map<int, BookmarkAppHelper::BitmapAndSource>
-BookmarkAppHelper::ConstrainBitmapsToSizes(
-    const std::vector<BookmarkAppHelper::BitmapAndSource>& bitmaps,
-    const std::set<int>& sizes) {
-  std::map<int, BitmapAndSource> output_bitmaps;
-  std::map<int, BitmapAndSource> ordered_bitmaps;
-  for (const BitmapAndSource& bitmap_and_source : bitmaps) {
-    const SkBitmap& bitmap = bitmap_and_source.bitmap;
-    DCHECK(bitmap.width() == bitmap.height());
-    ordered_bitmaps[bitmap.width()] = bitmap_and_source;
-  }
-
-  if (ordered_bitmaps.size() > 0) {
-    for (const auto& size : sizes) {
-      // Find the closest not-smaller bitmap, or failing that use the largest
-      // icon available.
-      auto bitmaps_it = ordered_bitmaps.lower_bound(size);
-      if (bitmaps_it != ordered_bitmaps.end())
-        output_bitmaps[size] = bitmaps_it->second;
-      else
-        output_bitmaps[size] = ordered_bitmaps.rbegin()->second;
-
-      // Resize the bitmap if it does not exactly match the desired size.
-      if (output_bitmaps[size].bitmap.width() != size) {
-        output_bitmaps[size].bitmap = skia::ImageOperations::Resize(
-            output_bitmaps[size].bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
-            size, size);
-      }
-    }
-  }
-
-  return output_bitmaps;
-}
-
-// static
-void BookmarkAppHelper::GenerateIcon(
-    std::map<int, BookmarkAppHelper::BitmapAndSource>* bitmaps,
-    int output_size,
-    SkColor color,
-    char letter) {
-  // Do nothing if there is already an icon of |output_size|.
-  if (bitmaps->count(output_size))
-    return;
-
-  (*bitmaps)[output_size].bitmap = GenerateBitmap(output_size, color, letter);
-}
-
-// static
 WebApplicationInfo::IconInfo BookmarkAppHelper::GenerateIconInfo(
     int output_size,
     SkColor color,
@@ -438,7 +279,7 @@
   WebApplicationInfo::IconInfo icon_info;
   icon_info.width = output_size;
   icon_info.height = output_size;
-  icon_info.data = GenerateBitmap(output_size, color, letter);
+  icon_info.data = web_app::GenerateBitmap(output_size, color, letter);
   return icon_info;
 }
 
@@ -464,47 +305,25 @@
 }
 
 // static
-std::map<int, BookmarkAppHelper::BitmapAndSource>
+std::map<int, web_app::BitmapAndSource>
 BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-    std::vector<BookmarkAppHelper::BitmapAndSource> icons,
+    std::vector<web_app::BitmapAndSource> icons,
     std::set<int> sizes_to_generate,
     WebApplicationInfo* web_app_info) {
-  // Resize provided icons to make sure we have versions for each size in
-  // |sizes_to_generate|.
-  std::map<int, BitmapAndSource> resized_bitmaps(
-      ConstrainBitmapsToSizes(icons, sizes_to_generate));
+  SkColor generated_icon_color = SK_ColorTRANSPARENT;
 
-  // Also add all provided icon sizes.
-  for (const BitmapAndSource& icon : icons) {
-    if (resized_bitmaps.find(icon.bitmap.width()) == resized_bitmaps.end())
-      resized_bitmaps.insert(std::make_pair(icon.bitmap.width(), icon));
-  }
+  std::map<int, web_app::BitmapAndSource> resized_bitmaps =
+      web_app::ResizeIconsAndGenerateMissing(icons, sizes_to_generate,
+                                             web_app_info->app_url,
+                                             &generated_icon_color);
 
-  // Determine the color that will be used for the icon's background. For this
-  // the dominant color of the first icon found is used.
-  if (resized_bitmaps.size()) {
-    color_utils::GridSampler sampler;
-    web_app_info->generated_icon_color =
-        color_utils::CalculateKMeanColorOfBitmap(
-            resized_bitmaps.begin()->second.bitmap);
-  }
-
-  // Work out what icons we need to generate here. Icons are only generated if
-  // there is no icon in the required size.
-  std::set<int> generate_sizes;
-  for (int size : sizes_to_generate) {
-    if (resized_bitmaps.find(size) == resized_bitmaps.end())
-      generate_sizes.insert(size);
-  }
-  GenerateIcons(generate_sizes, web_app_info->app_url,
-                web_app_info->generated_icon_color, &resized_bitmaps);
-
+  web_app_info->generated_icon_color = generated_icon_color;
   return resized_bitmaps;
 }
 
 // static
 void BookmarkAppHelper::UpdateWebAppIconsWithoutChangingLinks(
-    std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
+    std::map<int, web_app::BitmapAndSource> bitmap_map,
     WebApplicationInfo* web_app_info) {
   // First add in the icon data that have urls with the url / size data from the
   // original web app info, and the data from the new icons (if any).
@@ -528,17 +347,6 @@
   }
 }
 
-BookmarkAppHelper::BitmapAndSource::BitmapAndSource() {
-}
-
-BookmarkAppHelper::BitmapAndSource::BitmapAndSource(const GURL& source_url_p,
-                                                    const SkBitmap& bitmap_p)
-    : source_url(source_url_p),
-      bitmap(bitmap_p) {
-}
-
-BookmarkAppHelper::BitmapAndSource::~BitmapAndSource() {
-}
 
 BookmarkAppHelper::BookmarkAppHelper(Profile* profile,
                                      WebApplicationInfo web_app_info,
@@ -676,13 +484,14 @@
     return;
   }
 
-  std::vector<BitmapAndSource> downloaded_icons;
+  std::vector<web_app::BitmapAndSource> downloaded_icons;
   for (const std::pair<GURL, std::vector<SkBitmap>>& url_bitmap : bitmaps) {
     for (const SkBitmap& bitmap : url_bitmap.second) {
       if (bitmap.empty() || bitmap.width() != bitmap.height())
         continue;
 
-      downloaded_icons.push_back(BitmapAndSource(url_bitmap.first, bitmap));
+      downloaded_icons.push_back(
+          web_app::BitmapAndSource(url_bitmap.first, bitmap));
     }
   }
 
@@ -690,7 +499,7 @@
   for (const WebApplicationInfo::IconInfo& icon_info : web_app_info_.icons) {
     const SkBitmap& icon = icon_info.data;
     if (!icon.drawsNothing() && icon.width() == icon.height()) {
-      downloaded_icons.push_back(BitmapAndSource(icon_info.url, icon));
+      downloaded_icons.push_back(web_app::BitmapAndSource(icon_info.url, icon));
     }
   }
 
@@ -698,8 +507,9 @@
   // icons down to smaller sizes, and generating icons for sizes where resizing
   // is not possible.
   web_app_info_.generated_icon_color = SK_ColorTRANSPARENT;
-  std::map<int, BitmapAndSource> size_to_icons = ResizeIconsAndGenerateMissing(
-      downloaded_icons, SizesToGenerate(), &web_app_info_);
+  std::map<int, web_app::BitmapAndSource> size_to_icons =
+      ResizeIconsAndGenerateMissing(downloaded_icons, SizesToGenerate(),
+                                    &web_app_info_);
   ReplaceWebAppIcons(size_to_icons, &web_app_info_);
   web_app_icon_downloader_.reset();
 
diff --git a/chrome/browser/extensions/bookmark_app_helper.h b/chrome/browser/extensions/bookmark_app_helper.h
index 31827d5a0..382dd3c9 100644
--- a/chrome/browser/extensions/bookmark_app_helper.h
+++ b/chrome/browser/extensions/bookmark_app_helper.h
@@ -15,6 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/installable/installable_metrics.h"
+#include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/common/web_application_info.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -45,15 +46,6 @@
     kUnknown,
   };
 
-  struct BitmapAndSource {
-    BitmapAndSource();
-    BitmapAndSource(const GURL& source_url_p, const SkBitmap& bitmap_p);
-    ~BitmapAndSource();
-
-    GURL source_url;
-    SkBitmap bitmap;
-  };
-
   typedef base::Callback<void(const Extension*, const WebApplicationInfo&)>
       CreateBookmarkAppCallback;
 
@@ -75,24 +67,10 @@
                                            WebApplicationInfo* web_app_info,
                                            ForInstallableSite installable_site);
 
-  // This finds the closest not-smaller bitmap in |bitmaps| for each size in
-  // |sizes| and resizes it to that size. This returns a map of sizes to bitmaps
-  // which contains only bitmaps of a size in |sizes| and at most one bitmap of
-  // each size.
-  static std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
-      const std::vector<BitmapAndSource>& bitmaps,
-      const std::set<int>& sizes);
-
   // Adds a square container icon of |output_size| and 2 * |output_size| pixels
   // to |bitmaps| by drawing the given |letter| into a rounded background of
   // |color|. For each size, if an icon of the requested size already exists in
-  // |bitmaps|, nothing will happen.
-  static void GenerateIcon(std::map<int, BitmapAndSource>* bitmaps,
-                           int output_size,
-                           SkColor color,
-                           char letter);
-
-  // Same as above, but the generated icon is returned in a
+  // |bitmaps|, nothing will happen. The generated icon is returned in a
   // `WebApplicationInfo::IconInfo`.
   static WebApplicationInfo::IconInfo GenerateIconInfo(int output_size,
                                                        SkColor color,
@@ -105,8 +83,8 @@
 
   // Resize icons to the accepted sizes, and generate any that are missing. Does
   // not update |web_app_info| except to update |generated_icon_color|.
-  static std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
-      std::vector<BitmapAndSource> icons,
+  static std::map<int, web_app::BitmapAndSource> ResizeIconsAndGenerateMissing(
+      std::vector<web_app::BitmapAndSource> icons,
       std::set<int> sizes_to_generate,
       WebApplicationInfo* web_app_info);
 
@@ -118,7 +96,7 @@
   // |bitmap_map| that has a URL and size matching that in |web_app_info|, as
   // well as adding any new images from |bitmap_map| that have no URL.
   static void UpdateWebAppIconsWithoutChangingLinks(
-      std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
+      std::map<int, web_app::BitmapAndSource> bitmap_map,
       WebApplicationInfo* web_app_info);
 
   // Begins the asynchronous bookmark app creation.
diff --git a/chrome/browser/extensions/bookmark_app_helper_unittest.cc b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
index 3255caa..4c430cf 100644
--- a/chrome/browser/extensions/bookmark_app_helper_unittest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
@@ -53,18 +53,11 @@
 const char kAppIcon3[] = "fav3.png";
 const char kAppIconURL1[] = "http://foo.com/1.png";
 const char kAppIconURL2[] = "http://foo.com/2.png";
-const char kAppIconURL3[] = "http://foo.com/3.png";
-const char kAppIconURL4[] = "http://foo.com/4.png";
 
 const int kIconSizeTiny = extension_misc::EXTENSION_ICON_BITTY;
 const int kIconSizeSmall = extension_misc::EXTENSION_ICON_SMALL;
 const int kIconSizeMedium = extension_misc::EXTENSION_ICON_MEDIUM;
 const int kIconSizeLarge = extension_misc::EXTENSION_ICON_LARGE;
-const int kIconSizeGigantor = extension_misc::EXTENSION_ICON_GIGANTOR;
-const int kIconSizeUnsupported = 123;
-
-const int kIconSizeSmallBetweenMediumAndLarge = 63;
-const int kIconSizeLargeBetweenMediumAndLarge = 96;
 
 class BookmarkAppHelperTest : public testing::Test {
  public:
@@ -112,20 +105,6 @@
   return bitmap;
 }
 
-BookmarkAppHelper::BitmapAndSource CreateSquareBitmapAndSourceWithColor(
-    int size,
-    SkColor color) {
-  return BookmarkAppHelper::BitmapAndSource(
-      GURL(), CreateSquareBitmapWithColor(size, color));
-}
-
-void ValidateBitmapSizeAndColor(SkBitmap bitmap, int size, SkColor color) {
-  // Obtain pixel lock to access pixels.
-  EXPECT_EQ(color, bitmap.getColor(0, 0));
-  EXPECT_EQ(size, bitmap.width());
-  EXPECT_EQ(size, bitmap.height());
-}
-
 WebApplicationInfo::IconInfo CreateIconInfoWithBitmap(int size, SkColor color) {
   WebApplicationInfo::IconInfo icon_info;
   icon_info.width = size;
@@ -134,152 +113,6 @@
   return icon_info;
 }
 
-std::set<int> TestSizesToGenerate() {
-  const int kIconSizesToGenerate[] = {
-      extension_misc::EXTENSION_ICON_SMALL,
-      extension_misc::EXTENSION_ICON_MEDIUM,
-      extension_misc::EXTENSION_ICON_LARGE,
-  };
-  return std::set<int>(kIconSizesToGenerate,
-                       kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
-}
-
-void ValidateAllIconsWithURLsArePresent(const WebApplicationInfo& info_to_check,
-                                        const WebApplicationInfo& other_info) {
-  for (const auto& icon : info_to_check.icons) {
-    if (!icon.url.is_empty()) {
-      bool found = false;
-      for (const auto& other_icon : info_to_check.icons) {
-        if (other_icon.url == icon.url && other_icon.width == icon.width) {
-          found = true;
-          break;
-        }
-      }
-      EXPECT_TRUE(found);
-    }
-  }
-}
-
-std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator
-FindLargestBitmapAndSourceVector(
-    const std::vector<BookmarkAppHelper::BitmapAndSource>& bitmap_vector) {
-  auto result = bitmap_vector.end();
-  int largest = -1;
-  for (std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator it =
-           bitmap_vector.begin();
-       it != bitmap_vector.end(); ++it) {
-    if (it->bitmap.width() > largest) {
-      result = it;
-    }
-  }
-  return result;
-}
-
-std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator
-FindMatchingBitmapAndSourceVector(
-    const std::vector<BookmarkAppHelper::BitmapAndSource>& bitmap_vector,
-    int size) {
-  for (std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator it =
-           bitmap_vector.begin();
-       it != bitmap_vector.end(); ++it) {
-    if (it->bitmap.width() == size) {
-      return it;
-    }
-  }
-  return bitmap_vector.end();
-}
-
-std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator
-FindEqualOrLargerBitmapAndSourceVector(
-    const std::vector<BookmarkAppHelper::BitmapAndSource>& bitmap_vector,
-    int size) {
-  for (std::vector<BookmarkAppHelper::BitmapAndSource>::const_iterator it =
-           bitmap_vector.begin();
-       it != bitmap_vector.end(); ++it) {
-    if (it->bitmap.width() >= size) {
-      return it;
-    }
-  }
-  return bitmap_vector.end();
-}
-
-void ValidateIconsGeneratedAndResizedCorrectly(
-    std::vector<BookmarkAppHelper::BitmapAndSource> downloaded,
-    std::map<int, BookmarkAppHelper::BitmapAndSource> size_map,
-    std::set<int> sizes_to_generate,
-    int expected_generated,
-    int expected_resized) {
-  GURL empty_url("");
-  int number_generated = 0;
-  int number_resized = 0;
-
-  auto icon_largest = FindLargestBitmapAndSourceVector(downloaded);
-  for (const auto& size : sizes_to_generate) {
-    auto icon_downloaded = FindMatchingBitmapAndSourceVector(downloaded, size);
-    auto icon_larger = FindEqualOrLargerBitmapAndSourceVector(downloaded, size);
-    if (icon_downloaded == downloaded.end()) {
-      auto icon_resized = size_map.find(size);
-      if (icon_largest == downloaded.end()) {
-        // There are no downloaded icons. Expect an icon to be generated.
-        EXPECT_NE(size_map.end(), icon_resized);
-        EXPECT_EQ(size, icon_resized->second.bitmap.width());
-        EXPECT_EQ(size, icon_resized->second.bitmap.height());
-        EXPECT_EQ(size, icon_resized->second.bitmap.height());
-        EXPECT_EQ(empty_url, icon_resized->second.source_url);
-        ++number_generated;
-      } else {
-        // If there is a larger downloaded icon, it should be resized. Otherwise
-        // the largest downloaded icon should be resized.
-        auto icon_to_resize = icon_largest;
-        if (icon_larger != downloaded.end())
-          icon_to_resize = icon_larger;
-        EXPECT_NE(size_map.end(), icon_resized);
-        EXPECT_EQ(size, icon_resized->second.bitmap.width());
-        EXPECT_EQ(size, icon_resized->second.bitmap.height());
-        EXPECT_EQ(size, icon_resized->second.bitmap.height());
-        EXPECT_EQ(icon_to_resize->source_url, icon_resized->second.source_url);
-        ++number_resized;
-      }
-    } else {
-      // There is an icon of exactly this size downloaded. Expect no icon to be
-      // generated, and the existing downloaded icon to be used.
-      auto icon_resized = size_map.find(size);
-      EXPECT_NE(size_map.end(), icon_resized);
-      EXPECT_EQ(size, icon_resized->second.bitmap.width());
-      EXPECT_EQ(size, icon_resized->second.bitmap.height());
-      EXPECT_EQ(size, icon_downloaded->bitmap.width());
-      EXPECT_EQ(size, icon_downloaded->bitmap.height());
-      EXPECT_EQ(icon_downloaded->source_url, icon_resized->second.source_url);
-    }
-  }
-  EXPECT_EQ(expected_generated, number_generated);
-  EXPECT_EQ(expected_resized, number_resized);
-}
-
-void TestIconGeneration(int icon_size,
-                        int expected_generated,
-                        int expected_resized) {
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-
-  // Add an icon with a URL and bitmap. 'Download' it.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(icon_size, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  // Now run the resizing/generation and validation.
-  WebApplicationInfo web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &web_app_info);
-
-  ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
-                                            TestSizesToGenerate(),
-                                            expected_generated,
-                                            expected_resized);
-}
-
 class TestBookmarkAppHelper : public BookmarkAppHelper {
  public:
   TestBookmarkAppHelper(ExtensionService* service,
@@ -691,53 +524,6 @@
   }
 }
 
-TEST_F(BookmarkAppHelperExtensionServiceTest, LinkedAppIconsAreNotChanged) {
-  WebApplicationInfo web_app_info;
-
-  // Add two icons with a URL and bitmap, two icons with just a bitmap, an
-  // icon with just URL and an icon in an unsupported size with just a URL.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-  web_app_info.icons.push_back(icon_info);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeMedium, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL2);
-  web_app_info.icons.push_back(icon_info);
-
-  icon_info.data = SkBitmap();
-  icon_info.url = GURL(kAppIconURL3);
-  icon_info.width = 0;
-  icon_info.height = 0;
-  web_app_info.icons.push_back(icon_info);
-
-  icon_info.url = GURL(kAppIconURL4);
-  web_app_info.icons.push_back(icon_info);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED);
-  web_app_info.icons.push_back(icon_info);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeUnsupported, SK_ColorRED);
-  web_app_info.icons.push_back(icon_info);
-
-  // 'Download' one of the icons without a size or bitmap.
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-      GURL(kAppIconURL3),
-      CreateSquareBitmapWithColor(kIconSizeLarge, SK_ColorBLACK)));
-
-  // Now run the resizing and generation into a new web app info.
-  WebApplicationInfo new_web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &new_web_app_info);
-
-  // Now check that the linked app icons (i.e. those with URLs) are matching in
-  // both lists.
-  ValidateAllIconsWithURLsArePresent(web_app_info, new_web_app_info);
-  ValidateAllIconsWithURLsArePresent(new_web_app_info, web_app_info);
-}
-
 TEST_F(BookmarkAppHelperTest, UpdateWebAppInfoFromManifest) {
   WebApplicationInfo web_app_info;
   web_app_info.title = base::UTF8ToUTF16(kAlternativeAppTitle);
@@ -812,53 +598,6 @@
   }
 }
 
-TEST_F(BookmarkAppHelperTest, ConstrainBitmapsToSizes) {
-  std::set<int> desired_sizes;
-  desired_sizes.insert(16);
-  desired_sizes.insert(32);
-  desired_sizes.insert(48);
-  desired_sizes.insert(96);
-  desired_sizes.insert(128);
-  desired_sizes.insert(256);
-
-  {
-    std::vector<BookmarkAppHelper::BitmapAndSource> bitmaps;
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(16, SK_ColorRED));
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(32, SK_ColorGREEN));
-    bitmaps.push_back(
-        CreateSquareBitmapAndSourceWithColor(144, SK_ColorYELLOW));
-
-    std::map<int, BookmarkAppHelper::BitmapAndSource> results(
-        BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
-
-    EXPECT_EQ(6u, results.size());
-    ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorRED);
-    ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorGREEN);
-    ValidateBitmapSizeAndColor(results[48].bitmap, 48, SK_ColorYELLOW);
-    ValidateBitmapSizeAndColor(results[96].bitmap, 96, SK_ColorYELLOW);
-    ValidateBitmapSizeAndColor(results[128].bitmap, 128, SK_ColorYELLOW);
-    ValidateBitmapSizeAndColor(results[256].bitmap, 256, SK_ColorYELLOW);
-  }
-  {
-    std::vector<BookmarkAppHelper::BitmapAndSource> bitmaps;
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(512, SK_ColorRED));
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(18, SK_ColorGREEN));
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(33, SK_ColorBLUE));
-    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(17, SK_ColorYELLOW));
-
-    std::map<int, BookmarkAppHelper::BitmapAndSource> results(
-        BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
-
-    EXPECT_EQ(6u, results.size());
-    ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorYELLOW);
-    ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorBLUE);
-    ValidateBitmapSizeAndColor(results[48].bitmap, 48, SK_ColorRED);
-    ValidateBitmapSizeAndColor(results[96].bitmap, 96, SK_ColorRED);
-    ValidateBitmapSizeAndColor(results[128].bitmap, 128, SK_ColorRED);
-    ValidateBitmapSizeAndColor(results[256].bitmap, 256, SK_ColorRED);
-  }
-}
-
 TEST_F(BookmarkAppHelperTest, IsValidBookmarkAppUrl) {
   EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("https://chromium.org")));
   EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("https://www.chromium.org")));
@@ -879,140 +618,4 @@
   EXPECT_FALSE(IsValidBookmarkAppUrl(GURL("chrome://extensions")));
 }
 
-TEST_F(BookmarkAppHelperTest, IconsResizedFromOddSizes) {
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-
-  // Add three icons with a URL and bitmap. 'Download' each of them.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeSmallBetweenMediumAndLarge,
-                                       SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL2);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeLargeBetweenMediumAndLarge,
-                                       SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL3);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  // Now run the resizing and generation.
-  WebApplicationInfo web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &web_app_info);
-
-  // No icons should be generated. The LARGE and MEDIUM sizes should be resized.
-  ValidateIconsGeneratedAndResizedCorrectly(
-      downloaded, size_map, TestSizesToGenerate(), 0, 2);
-}
-
-TEST_F(BookmarkAppHelperTest, IconsResizedFromLarger) {
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-
-  // Add three icons with a URL and bitmap. 'Download' two of them and pretend
-  // the third failed to download.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorBLUE);
-  icon_info.url = GURL(kAppIconURL2);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
-  icon_info.url = GURL(kAppIconURL3);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  // Now run the resizing and generation.
-  WebApplicationInfo web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &web_app_info);
-
-  // Expect icon for MEDIUM and LARGE to be resized from the gigantor icon
-  // as it was not downloaded.
-  ValidateIconsGeneratedAndResizedCorrectly(
-      downloaded, size_map, TestSizesToGenerate(), 0, 2);
-}
-
-TEST_F(BookmarkAppHelperTest, AllIconsGeneratedWhenNotDownloaded) {
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-
-  // Add three icons with a URL and bitmap. 'Download' none of them.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorBLUE);
-  icon_info.url = GURL(kAppIconURL2);
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
-  icon_info.url = GURL(kAppIconURL3);
-
-  // Now run the resizing and generation.
-  WebApplicationInfo web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &web_app_info);
-
-  // Expect all icons to be generated.
-  ValidateIconsGeneratedAndResizedCorrectly(
-      downloaded, size_map, TestSizesToGenerate(), 3, 0);
-}
-
-TEST_F(BookmarkAppHelperTest, IconResizedFromLargerAndSmaller) {
-  std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
-
-  // Pretend the huge icon wasn't downloaded but two smaller ones were.
-  WebApplicationInfo::IconInfo icon_info =
-      CreateIconInfoWithBitmap(kIconSizeTiny, SK_ColorRED);
-  icon_info.url = GURL(kAppIconURL1);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeMedium, SK_ColorBLUE);
-  icon_info.url = GURL(kAppIconURL2);
-  downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
-        icon_info.url, icon_info.data));
-
-  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
-  icon_info.url = GURL(kAppIconURL3);
-
-  // Now run the resizing and generation.
-  WebApplicationInfo web_app_info;
-  std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
-      BookmarkAppHelper::ResizeIconsAndGenerateMissing(
-          downloaded, TestSizesToGenerate(), &web_app_info);
-
-  // Expect no icons to be generated, but the LARGE and SMALL icons to be
-  // resized from the MEDIUM icon.
-  ValidateIconsGeneratedAndResizedCorrectly(
-      downloaded, size_map, TestSizesToGenerate(), 0, 2);
-
-  // Verify specifically that the LARGE icons was resized from the medium icon.
-  const auto it = size_map.find(kIconSizeLarge);
-  EXPECT_NE(size_map.end(), it);
-  EXPECT_EQ(GURL(kAppIconURL2), it->second.source_url);
-}
-
-TEST_F(BookmarkAppHelperTest, IconsResizedWhenOnlyATinyOneIsProvided) {
-  // When only a tiny icon is downloaded (smaller than the three desired
-  // sizes), 3 icons should be resized.
-  TestIconGeneration(kIconSizeTiny, 0, 3);
-}
-
-TEST_F(BookmarkAppHelperTest, IconsResizedWhenOnlyAGigantorOneIsProvided) {
-  // When an enormous icon is provided, each desired icon size should be resized
-  // from it, and no icons should be generated.
-  TestIconGeneration(kIconSizeGigantor, 0, 3);
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/extensions/dev_mode_bubble_delegate.cc b/chrome/browser/extensions/dev_mode_bubble_delegate.cc
index 0be3704..2cb5204 100644
--- a/chrome/browser/extensions/dev_mode_bubble_delegate.cc
+++ b/chrome/browser/extensions/dev_mode_bubble_delegate.cc
@@ -17,7 +17,6 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_system.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/ui_features.h"
 
 namespace extensions {
@@ -76,13 +75,6 @@
 }
 
 base::string16 DevModeBubbleDelegate::GetDismissButtonLabel() const {
-// TODO(https://crbug.com/671656): Keep the cancel button on MACOSX unless
-// using views or the Cocoa version is updated.
-#if defined(OS_MACOSX)
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial())
-    return l10n_util::GetStringUTF16(IDS_CANCEL);
-#endif
-
   return base::string16();
 }
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 99567696..7dd201c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -443,6 +443,11 @@
 const char kEnableCaptivePortalRandomUrlDescription[] =
     "Enable Captive Portal URL randomization.";
 
+const char kEnableChromevoxDeveloperOptionName[] =
+    "Enable Chromevox developer option";
+const char kEnableChromevoxDeveloperOptionDescription[] =
+    "This option provides tools for developing in chromevox.";
+
 const char kEnableClientLoFiName[] = "Client-side Lo-Fi previews";
 
 const char kEnableClientLoFiDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index da903110..feb88988 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -299,6 +299,9 @@
 extern const char kEnableCaptivePortalRandomUrl[];
 extern const char kEnableCaptivePortalRandomUrlDescription[];
 
+extern const char kEnableChromevoxDeveloperOptionName[];
+extern const char kEnableChromevoxDeveloperOptionDescription[];
+
 extern const char kEnableClientLoFiName[];
 extern const char kEnableClientLoFiDescription[];
 
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm
index 86402d4..0cfb801 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac.mm
+++ b/chrome/browser/global_keyboard_shortcuts_mac.mm
@@ -18,11 +18,28 @@
 #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
 #include "chrome/browser/ui/views_mode_controller.h"
 #include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/platform_accelerator_cocoa.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/keyboard_code_conversion_mac.h"
 
 namespace {
 
+// Returns a ui::Accelerator given a KeyboardShortcutData.
+ui::Accelerator AcceleratorFromShortcut(const KeyboardShortcutData& shortcut) {
+  int modifiers = 0;
+  if (shortcut.command_key)
+    modifiers |= ui::EF_COMMAND_DOWN;
+  if (shortcut.shift_key)
+    modifiers |= ui::EF_SHIFT_DOWN;
+  if (shortcut.cntrl_key)
+    modifiers |= ui::EF_CONTROL_DOWN;
+  if (shortcut.opt_key)
+    modifiers |= ui::EF_ALT_DOWN;
+
+  return ui::Accelerator(ui::KeyboardCodeFromKeyCode(shortcut.vkey_code),
+                         modifiers);
+}
+
 // Returns the menu item associated with |key| in |menu|, or nil if not found.
 NSMenuItem* FindMenuItem(NSEvent* key, NSMenu* menu) {
   NSMenuItem* result = nil;
@@ -154,6 +171,30 @@
   return *keys;
 }
 
+const std::vector<NSMenuItem*>& GetMenuItemsNotPresentInMainMenu() {
+  static base::NoDestructor<std::vector<NSMenuItem*>> menu_items;
+  if (menu_items->empty()) {
+    for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
+      ui::Accelerator accelerator = AcceleratorFromShortcut(shortcut);
+      NSString* key_equivalent = nil;
+      NSUInteger modifier_mask = 0;
+      ui::GetKeyEquivalentAndModifierMaskFromAccelerator(
+          accelerator, &key_equivalent, &modifier_mask);
+
+      // Intentionally leaked!
+      NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:@""
+                                                    action:NULL
+                                             keyEquivalent:key_equivalent];
+      item.keyEquivalentModifierMask = modifier_mask;
+
+      // We store the command in the tag.
+      item.tag = shortcut.chrome_command;
+      menu_items->push_back(item);
+    }
+  }
+  return *menu_items;
+}
+
 CommandForKeyEventResult CommandForKeyEvent(NSEvent* event) {
   DCHECK(event);
   if ([event type] != NSKeyDown)
@@ -163,21 +204,11 @@
   if (cmdNum != -1)
     return MainMenuCommand(cmdNum);
 
-  // Look in secondary keyboard shortcuts.
-  NSUInteger modifiers = [event modifierFlags];
-  const bool cmdKey = (modifiers & NSCommandKeyMask) != 0;
-  const bool shiftKey = (modifiers & NSShiftKeyMask) != 0;
-  const bool cntrlKey = (modifiers & NSControlKeyMask) != 0;
-  const bool optKey = (modifiers & NSAlternateKeyMask) != 0;
-  const int keyCode = [event keyCode];
-
   // Scan through keycodes and see if it corresponds to one of the non-menu
   // shortcuts.
-  for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
-    if (MatchesEventForKeyboardShortcut(shortcut, cmdKey, shiftKey, cntrlKey,
-                                        optKey, keyCode)) {
-      return ShortcutCommand(shortcut.chrome_command);
-    }
+  for (NSMenuItem* menu_item : GetMenuItemsNotPresentInMainMenu()) {
+    if ([menu_item cr_firesForKeyEvent:event])
+      return ShortcutCommand(menu_item.tag);
   }
 
   return NoCommand();
@@ -226,18 +257,7 @@
   // See if it corresponds to one of the non-menu shortcuts.
   for (const auto& shortcut : GetShortcutsNotPresentInMainMenu()) {
     if (shortcut.chrome_command == command_id) {
-      int modifiers = 0;
-      if (shortcut.command_key)
-        modifiers |= ui::EF_COMMAND_DOWN;
-      if (shortcut.shift_key)
-        modifiers |= ui::EF_SHIFT_DOWN;
-      if (shortcut.cntrl_key)
-        modifiers |= ui::EF_CONTROL_DOWN;
-      if (shortcut.opt_key)
-        modifiers |= ui::EF_ALT_DOWN;
-
-      *accelerator = ui::Accelerator(
-          ui::KeyboardCodeFromKeyCode(shortcut.vkey_code), modifiers);
+      *accelerator = AcceleratorFromShortcut(shortcut);
       return true;
     }
   }
diff --git a/chrome/browser/global_keyboard_shortcuts_mac_unittest.mm b/chrome/browser/global_keyboard_shortcuts_mac_unittest.mm
index efd5857..df9f519 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac_unittest.mm
+++ b/chrome/browser/global_keyboard_shortcuts_mac_unittest.mm
@@ -13,6 +13,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_features.h"
+#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
 
 namespace {
 
@@ -31,19 +32,25 @@
   if (opt_key)
     modifierFlags |= NSAlternateKeyMask;
 
-  // Use a two-length string as a dummy character.
-  NSString* chars = @"ab";
+  unichar shifted_character;
+  unichar character;
+  int result = ui::MacKeyCodeForWindowsKeyCode(
+      ui::KeyboardCodeFromKeyCode(vkey_code), modifierFlags, &shifted_character,
+      &character);
+  DCHECK_NE(result, -1);
 
-  NSEvent* event = [NSEvent keyEventWithType:NSKeyDown
-                                    location:NSZeroPoint
-                               modifierFlags:modifierFlags
-                                   timestamp:0.0
-                                windowNumber:0
-                                     context:nil
-                                  characters:chars
-                 charactersIgnoringModifiers:chars
-                                   isARepeat:NO
-                                     keyCode:vkey_code];
+  NSEvent* event = [NSEvent
+                 keyEventWithType:NSKeyDown
+                         location:NSZeroPoint
+                    modifierFlags:modifierFlags
+                        timestamp:0.0
+                     windowNumber:0
+                          context:nil
+                       characters:[NSString stringWithFormat:@"%C", character]
+      charactersIgnoringModifiers:[NSString
+                                      stringWithFormat:@"%C", shifted_character]
+                        isARepeat:NO
+                          keyCode:vkey_code];
 
   return CommandForKeyEvent(event).chrome_command;
 }
@@ -86,20 +93,21 @@
     {kVK_ANSI_9, kVK_ANSI_Keypad9},
   };
 
+  // We only consider unshifted keys. A shifted numpad key gives a different
+  // keyEquivalent than a shifted number key.
+  int shift = 0;
   for (unsigned int i = 0; i < base::size(equivalents); ++i) {
     for (int command = 0; command <= 1; ++command) {
-      for (int shift = 0; shift <= 1; ++shift) {
-        for (int control = 0; control <= 1; ++control) {
-          for (int option = 0; option <= 1; ++option) {
-            EXPECT_EQ(CommandForKeys(command, shift, control, option,
-                                     equivalents[i].keycode),
-                      CommandForKeys(command, shift, control, option,
-                                     equivalents[i].keypad_keycode));
-            EXPECT_EQ(CommandForKeys(command, shift, control, option,
-                                     equivalents[i].keycode),
-                      CommandForKeys(command, shift, control, option,
-                                     equivalents[i].keypad_keycode));
-          }
+      for (int control = 0; control <= 1; ++control) {
+        for (int option = 0; option <= 1; ++option) {
+          EXPECT_EQ(CommandForKeys(command, shift, control, option,
+                                   equivalents[i].keycode),
+                    CommandForKeys(command, shift, control, option,
+                                   equivalents[i].keypad_keycode));
+          EXPECT_EQ(CommandForKeys(command, shift, control, option,
+                                   equivalents[i].keycode),
+                    CommandForKeys(command, shift, control, option,
+                                   equivalents[i].keypad_keycode));
         }
       }
     }
diff --git a/chrome/browser/intranet_redirect_detector.cc b/chrome/browser/intranet_redirect_detector.cc
index b7c2862..283d0c2 100644
--- a/chrome/browser/intranet_redirect_detector.cc
+++ b/chrome/browser/intranet_redirect_detector.cc
@@ -22,6 +22,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -48,13 +49,11 @@
                      weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(kStartFetchDelaySeconds));
 
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 }
 
 IntranetRedirectDetector::~IntranetRedirectDetector() {
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 // static
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry.cc b/chrome/browser/media/router/discovery/dial/dial_registry.cc
index 9cb3142..889d7d61 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_registry.cc
@@ -12,10 +12,10 @@
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/discovery/dial/dial_service.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -49,8 +49,7 @@
   DCHECK_GT(max_devices_, 0U);
   BrowserThread::PostTaskAndReplyWithResult(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&BrowserProcess::network_connection_tracker,
-                     base::Unretained(g_browser_process)),
+      base::BindOnce(&content::GetNetworkConnectionTracker),
       base::BindOnce(&DialRegistry::SetNetworkConnectionTracker,
                      base::Unretained(this)));
 }
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor.cc b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
index a7074b9..75b250bf 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
@@ -16,9 +16,9 @@
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
 #include "base/time/default_tick_clock.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/discovery/discovery_network_list.h"
 #include "chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.h"
+#include "content/public/browser/network_service_instance.h"
 #include "net/base/network_interfaces.h"
 
 namespace media_router {
@@ -106,7 +106,7 @@
   DETACH_FROM_SEQUENCE(sequence_checker_);
   AddObserver(metric_observer_.get());
 
-  g_browser_process->network_connection_tracker()
+  content::GetNetworkConnectionTracker()
       ->AddLeakyNetworkConnectionObserver(this);
 
   task_runner_->PostTask(
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor_unittest.cc b/chrome/browser/media/router/discovery/discovery_network_monitor_unittest.cc
index f8a443e..ceb0b07 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor_unittest.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/task/task_scheduler/task_scheduler.h"
-#include "base/test/scoped_task_environment.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -31,7 +31,7 @@
     fake_network_info.clear();
     discovery_network_monitor =
         DiscoveryNetworkMonitor::CreateInstanceForTest(&FakeGetNetworkInfo);
-    scoped_task_environment.RunUntilIdle();
+    thread_bundle.RunUntilIdle();
   }
 
   static std::vector<DiscoveryNetworkInfo> FakeGetNetworkInfo() {
@@ -42,7 +42,7 @@
     discovery_network_monitor->OnConnectionChanged(connection_type);
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_environment;
+  content::TestBrowserThreadBundle thread_bundle;
   MockDiscoveryObserver mock_observer;
 
   std::vector<DiscoveryNetworkInfo> fake_ethernet_info{
@@ -72,7 +72,7 @@
       .WillOnce(Invoke(capture_network_id));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   std::string ethernet_network_id = current_network_id;
 
@@ -81,14 +81,14 @@
       .WillOnce(Invoke(capture_network_id));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_NONE);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   fake_network_info = fake_wifi_info;
   EXPECT_CALL(mock_observer, OnNetworksChanged(_))
       .WillOnce(Invoke(capture_network_id));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_WIFI);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   std::string wifi_network_id = current_network_id;
   fake_network_info = fake_ethernet_info;
@@ -96,7 +96,7 @@
       .WillOnce(Invoke(capture_network_id));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   EXPECT_EQ(ethernet_network_id, current_network_id);
   EXPECT_NE(ethernet_network_id, wifi_network_id);
@@ -111,13 +111,13 @@
   EXPECT_CALL(mock_observer, OnNetworksChanged(_));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   discovery_network_monitor->RemoveObserver(&mock_observer);
   fake_network_info.clear();
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_NONE);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 }
 
 TEST_F(DiscoveryNetworkMonitorTest, RefreshIndependentOfChangeObserver) {
@@ -133,11 +133,11 @@
   };
 
   discovery_network_monitor->Refresh(base::BindOnce(force_refresh_callback));
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 }
 
 TEST_F(DiscoveryNetworkMonitorTest, GetNetworkIdWithoutRefresh) {
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   fake_network_info = fake_ethernet_info;
 
@@ -145,7 +145,7 @@
     EXPECT_EQ(DiscoveryNetworkMonitor::kNetworkIdDisconnected, network_id);
   };
   discovery_network_monitor->GetNetworkId(base::BindOnce(check_network_id));
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 }
 
 TEST_F(DiscoveryNetworkMonitorTest, GetNetworkIdWithRefresh) {
@@ -162,7 +162,7 @@
   };
   discovery_network_monitor->Refresh(
       base::BindOnce(capture_network_id, &current_network_id));
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   auto check_network_id = [](const std::string& refresh_network_id,
                              const std::string& network_id) {
@@ -170,7 +170,7 @@
   };
   discovery_network_monitor->GetNetworkId(
       base::BindOnce(check_network_id, base::ConstRef(current_network_id)));
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 }
 
 TEST_F(DiscoveryNetworkMonitorTest, GetNetworkIdWithObserver) {
@@ -180,7 +180,7 @@
   EXPECT_CALL(mock_observer, OnNetworksChanged(_));
 
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 
   std::string current_network_id;
   auto check_network_id = [](const std::string& network_id) {
@@ -190,7 +190,7 @@
               network_id);
   };
   discovery_network_monitor->GetNetworkId(base::BindOnce(check_network_id));
-  scoped_task_environment.RunUntilIdle();
+  thread_bundle.RunUntilIdle();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
index eae926aa..f4c8e72 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -13,6 +13,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/render_process_host.h"
 
 namespace {
@@ -527,7 +528,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   network::NetworkConnectionTracker* network_connection_tracker =
-      g_browser_process->network_connection_tracker();
+      content::GetNetworkConnectionTracker();
   DCHECK(network_connection_tracker);
 
   net::URLRequestContextGetter* url_request_context_getter =
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
index b9258c94..1cf5a9c4 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
@@ -47,6 +47,7 @@
 #include "components/prefs/testing_pref_store.h"
 #include "components/sync_preferences/pref_service_mock_factory.h"
 #include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/url_request/url_request_test_util.h"
@@ -235,8 +236,9 @@
   }
 
   void SetUp(std::unique_ptr<network::NetworkConnectionTracker> tracker) {
-    TestingBrowserProcess::GetGlobal()->SetNetworkConnectionTracker(
-        std::move(tracker));
+    network_connection_tracker_ = std::move(tracker);
+    content::SetNetworkConnectionTrackerForTesting(
+        network_connection_tracker_.get());
     SetLocalLogsObserver(&local_observer_);
     SetRemoteLogsObserver(&remote_observer_);
     LoadMainTestProfile();
@@ -674,6 +676,10 @@
   // Unit under test.
   std::unique_ptr<WebRtcEventLogManager> event_log_manager_;
 
+  // The NetworkConnectionTracker instance used by the WebRtcEventLogManager.
+  std::unique_ptr<network::NetworkConnectionTracker>
+      network_connection_tracker_;
+
   // Extensions associated with local/remote-bound event logs. Depends on
   // whether they're compressed.
   base::FilePath::StringPieceType local_log_extension_;
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index a0f6ff69..e89716e 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -92,6 +92,7 @@
 #include "content/public/browser/notification_service.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -528,7 +529,7 @@
     metrics::MetricsLogUploader::MetricServiceType service_type,
     const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
   return std::make_unique<metrics::NetMetricsLogUploader>(
-      g_browser_process->system_request_context(), server_url,
+      g_browser_process->shared_url_loader_factory(), server_url,
       insecure_server_url, mime_type, service_type, on_upload_complete);
 }
 
diff --git a/chrome/browser/net/network_connection_tracker_browsertest.cc b/chrome/browser/net/network_connection_tracker_browsertest.cc
index 4038f2d..d26610db 100644
--- a/chrome/browser/net/network_connection_tracker_browsertest.cc
+++ b/chrome/browser/net/network_connection_tracker_browsertest.cc
@@ -10,11 +10,11 @@
 #include "base/sequence_checker.h"
 #include "base/test/bind_test_util.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
@@ -127,7 +127,7 @@
     return;
 #endif
   network::NetworkConnectionTracker* tracker =
-      g_browser_process->network_connection_tracker();
+      content::GetNetworkConnectionTracker();
   EXPECT_NE(nullptr, tracker);
   // Issue a GetConnectionType() request to make sure NetworkService has been
   // started up. This way, NetworkService will receive the broadcast when
@@ -162,7 +162,7 @@
     return;
 
   network::NetworkConnectionTracker* tracker =
-      g_browser_process->network_connection_tracker();
+      content::GetNetworkConnectionTracker();
   EXPECT_NE(nullptr, tracker);
 
   // Issue a GetConnectionType() request to make sure NetworkService has been
diff --git a/chrome/browser/net/variations_http_headers_browsertest.cc b/chrome/browser/net/variations_http_headers_browsertest.cc
index 859cc89..cac1650 100644
--- a/chrome/browser/net/variations_http_headers_browsertest.cc
+++ b/chrome/browser/net/variations_http_headers_browsertest.cc
@@ -6,10 +6,13 @@
 
 #include <map>
 
+#include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_browser_main.h"
+#include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -36,12 +39,34 @@
 
 namespace {
 
+class VariationHeaderSetter : public ChromeBrowserMainExtraParts {
+ public:
+  VariationHeaderSetter() = default;
+  ~VariationHeaderSetter() override = default;
+
+  // ChromeBrowserMainExtraParts:
+  void PostEarlyInitialization() override {
+    // Set up some fake variations.
+    auto* variations_provider =
+        variations::VariationsHttpHeaderProvider::GetInstance();
+    variations_provider->ForceVariationIds({"12", "456", "t789"}, "");
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VariationHeaderSetter);
+};
+
 class VariationsHttpHeadersBrowserTest : public InProcessBrowserTest {
  public:
   VariationsHttpHeadersBrowserTest()
       : https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {}
   ~VariationsHttpHeadersBrowserTest() override = default;
 
+  void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
+    static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
+        new VariationHeaderSetter());
+  }
+
   void SetUpOnMainThread() override {
     InProcessBrowserTest::SetUpOnMainThread();
 
@@ -52,11 +77,6 @@
                             base::Unretained(this)));
 
     ASSERT_TRUE(server()->Start());
-
-    // Set up some fake variations.
-    auto* variations_provider =
-        variations::VariationsHttpHeaderProvider::GetInstance();
-    variations_provider->ForceVariationIds({"12", "456", "t789"}, "");
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/payments/chrome_payment_request_delegate.cc b/chrome/browser/payments/chrome_payment_request_delegate.cc
index b0a4f63..47c7d76 100644
--- a/chrome/browser/payments/chrome_payment_request_delegate.cc
+++ b/chrome/browser/payments/chrome_payment_request_delegate.cc
@@ -63,9 +63,8 @@
 
 void ChromePaymentRequestDelegate::ShowDialog(PaymentRequest* request) {
   DCHECK_EQ(nullptr, shown_dialog_);
-  hidden_dialog_ = std::unique_ptr<PaymentRequestDialog>(
-      chrome::CreatePaymentRequestDialog(request));
-  MaybeShowHiddenDialog(request);
+  shown_dialog_ = chrome::CreatePaymentRequestDialog(request);
+  shown_dialog_->ShowDialog();
 }
 
 void ChromePaymentRequestDelegate::CloseDialog() {
@@ -73,9 +72,6 @@
     shown_dialog_->CloseDialog();
     shown_dialog_ = nullptr;
   }
-
-  if (hidden_dialog_)
-    hidden_dialog_.reset();
 }
 
 void ChromePaymentRequestDelegate::ShowErrorMessage() {
@@ -180,10 +176,7 @@
 void ChromePaymentRequestDelegate::EmbedPaymentHandlerWindow(
     const GURL& url,
     PaymentHandlerOpenWindowCallback callback) {
-  if (hidden_dialog_) {
-    shown_dialog_ = hidden_dialog_.release();
-    shown_dialog_->ShowDialogAtPaymentHandlerSheet(url, std::move(callback));
-  } else if (shown_dialog_) {
+  if (shown_dialog_) {
     shown_dialog_->ShowPaymentHandlerScreen(url, std::move(callback));
   } else {
     std::move(callback).Run(/*success=*/false,
@@ -192,14 +185,4 @@
   }
 }
 
-void ChromePaymentRequestDelegate::MaybeShowHiddenDialog(
-    PaymentRequest* request) {
-  if (request->SatisfiesSkipUIConstraints()) {
-    request->Pay();
-  } else {
-    shown_dialog_ = hidden_dialog_.release();
-    shown_dialog_->ShowDialog();
-  }
-}
-
 }  // namespace payments
diff --git a/chrome/browser/payments/chrome_payment_request_delegate.h b/chrome/browser/payments/chrome_payment_request_delegate.h
index 761c1c6..a519a5b6 100644
--- a/chrome/browser/payments/chrome_payment_request_delegate.h
+++ b/chrome/browser/payments/chrome_payment_request_delegate.h
@@ -58,21 +58,6 @@
   // for testing.
   PaymentRequestDialog* shown_dialog_;
 
-  // The instance of the dialog that was created but not shown yet. Since it
-  // hasn't been shown, it's still owned by it's creator. This is non null only
-  // when the current Payment Request supports skipping the payment sheet (see
-  // PaymentRequest::SatisfiesSkipUIConstraints) and is reset once the
-  // underlying pointer becomes owned by the views:: machinery (when the dialog
-  // is shown).
-  std::unique_ptr<PaymentRequestDialog> hidden_dialog_;
-
-  // Shows |hidden_dialog_| if the current Payment Request doesn't support the
-  // skip UI flow. This also transfer its ownership to the views dialog code and
-  // keep a reference to it in |shown_dialog_|.
-  // Otherwise, this calls Pay() on the current Payment Request to allow the
-  // skip UI flow to carry on.
-  void MaybeShowHiddenDialog(PaymentRequest* request);
-
  private:
   // Not owned but outlives the PaymentRequest object that owns this.
   content::WebContents* web_contents_;
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index c3e0e0b..042b3e15 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -253,7 +253,8 @@
 struct PermissionManager::Subscription {
   ContentSettingsType permission;
   GURL requesting_origin;
-  GURL embedding_origin;
+  int render_frame_id = -1;
+  int render_process_id = -1;
   base::Callback<void(ContentSetting)> callback;
   ContentSetting current_value;
 };
@@ -537,9 +538,7 @@
     GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
     result = context->UpdatePermissionStatusWithDeviceStatus(
         result, GetCanonicalOrigin(requesting_origin, embedding_origin),
-        content::WebContents::FromRenderFrameHost(render_frame_host)
-            ->GetLastCommittedURL()
-            .GetOrigin());
+        embedding_origin);
   }
 
   return ContentSettingToPermissionStatus(result.content_setting);
@@ -547,8 +546,8 @@
 
 int PermissionManager::SubscribePermissionStatusChange(
     PermissionType permission,
+    content::RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(PermissionStatus)>& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (subscriptions_.IsEmpty())
@@ -556,16 +555,33 @@
 
   ContentSettingsType content_type = PermissionTypeToContentSetting(permission);
   auto subscription = std::make_unique<Subscription>();
+
+  // The RFH may be null if the request is for a worker.
+  GURL embedding_origin;
+  if (render_frame_host) {
+    content::WebContents* web_contents =
+        content::WebContents::FromRenderFrameHost(render_frame_host);
+    embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
+    subscription->render_frame_id = render_frame_host->GetRoutingID();
+    subscription->render_process_id = render_frame_host->GetProcess()->GetID();
+    subscription->current_value =
+        GetPermissionStatusForFrame(content_type, render_frame_host,
+                                    requesting_origin)
+            .content_setting;
+  } else {
+    embedding_origin = requesting_origin;
+    subscription->render_frame_id = -1;
+    subscription->render_process_id = -1;
+    subscription->current_value =
+        GetPermissionStatus(content_type, requesting_origin, requesting_origin)
+            .content_setting;
+  }
+
   subscription->permission = content_type;
   subscription->requesting_origin =
       GetCanonicalOrigin(requesting_origin, embedding_origin);
-  subscription->embedding_origin = embedding_origin;
   subscription->callback = base::Bind(&SubscriptionCallbackWrapper, callback);
 
-  subscription->current_value =
-      GetPermissionStatus(content_type, requesting_origin, embedding_origin)
-          .content_setting;
-
   return subscriptions_.Add(std::move(subscription));
 }
 
@@ -599,18 +615,37 @@
     if (subscription->permission != content_type)
       continue;
 
+    // The RFH may be null if the request is for a worker.
+    content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
+        subscription->render_process_id, subscription->render_frame_id);
+    GURL embedding_origin;
+    if (rfh) {
+      content::WebContents* web_contents =
+          content::WebContents::FromRenderFrameHost(rfh);
+      embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
+    } else {
+      embedding_origin = subscription->requesting_origin;
+    }
+
     if (primary_pattern.IsValid() &&
         !primary_pattern.Matches(subscription->requesting_origin))
       continue;
     if (secondary_pattern.IsValid() &&
-        !secondary_pattern.Matches(subscription->embedding_origin))
+        !secondary_pattern.Matches(embedding_origin))
       continue;
 
-    ContentSetting new_value =
-        GetPermissionStatus(subscription->permission,
-                            subscription->requesting_origin,
-                            subscription->embedding_origin)
-            .content_setting;
+    ContentSetting new_value;
+    if (rfh) {
+      new_value = GetPermissionStatusForFrame(subscription->permission, rfh,
+                                              subscription->requesting_origin)
+                      .content_setting;
+    } else {
+      new_value = GetPermissionStatus(subscription->permission,
+                                      subscription->requesting_origin,
+                                      subscription->requesting_origin)
+                      .content_setting;
+    }
+
     if (subscription->current_value == new_value)
       continue;
 
diff --git a/chrome/browser/permissions/permission_manager.h b/chrome/browser/permissions/permission_manager.h
index beb9cae..223f67e 100644
--- a/chrome/browser/permissions/permission_manager.h
+++ b/chrome/browser/permissions/permission_manager.h
@@ -108,8 +108,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/chrome/browser/permissions/permission_manager_unittest.cc b/chrome/browser/permissions/permission_manager_unittest.cc
index 6cfbd058..8832ac6 100644
--- a/chrome/browser/permissions/permission_manager_unittest.cc
+++ b/chrome/browser/permissions/permission_manager_unittest.cc
@@ -140,6 +140,7 @@
         true /* has_android_location_permission */,
         true /* is_system_location_setting_enabled */);
 #endif
+    NavigateAndCommit(url());
   }
 
   void TearDown() override {
@@ -226,7 +227,7 @@
   // Test that the PermissionManager shuts down cleanly with subscriptions that
   // haven't been removed, crbug.com/720071.
   GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
+      PermissionType::GEOLOCATION, main_rfh(), url(),
       base::Bind(&PermissionManagerTest::OnPermissionChange,
                  base::Unretained(this)));
 }
@@ -234,7 +235,7 @@
 TEST_F(PermissionManagerTest, SameTypeChangeNotifies) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -252,7 +253,7 @@
 TEST_F(PermissionManagerTest, DifferentTypeChangeDoesNotNotify) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -269,7 +270,7 @@
 TEST_F(PermissionManagerTest, ChangeAfterUnsubscribeDoesNotNotify) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -286,7 +287,7 @@
 TEST_F(PermissionManagerTest, DifferentPrimaryUrlDoesNotNotify) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -303,7 +304,7 @@
 TEST_F(PermissionManagerTest, DifferentSecondaryUrlDoesNotNotify) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -320,7 +321,7 @@
 TEST_F(PermissionManagerTest, WildCardPatternNotifies) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -341,7 +342,7 @@
 
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -358,7 +359,7 @@
 TEST_F(PermissionManagerTest, NewValueCorrectlyPassed) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -380,7 +381,7 @@
 
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -401,7 +402,38 @@
 
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::GEOLOCATION, url(), url(),
+          PermissionType::GEOLOCATION, main_rfh(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
+
+  GetHostContentSettingsMap()->SetContentSettingDefaultScope(
+      url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
+      CONTENT_SETTING_ALLOW);
+
+  EXPECT_TRUE(callback_called());
+  EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
+
+  Reset();
+
+  GetHostContentSettingsMap()->SetContentSettingDefaultScope(
+      url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
+      CONTENT_SETTING_ASK);
+
+  EXPECT_TRUE(callback_called());
+  EXPECT_EQ(PermissionStatus::ASK, callback_result());
+
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
+}
+
+TEST_F(PermissionManagerTest, ChangesBackAndForthWorker) {
+  GetHostContentSettingsMap()->SetContentSettingDefaultScope(
+      url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
+      CONTENT_SETTING_ASK);
+
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, nullptr, url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
@@ -428,7 +460,7 @@
 TEST_F(PermissionManagerTest, SubscribeMIDIPermission) {
   int subscription_id =
       GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
-          PermissionType::MIDI, url(), url(),
+          PermissionType::MIDI, main_rfh(), url(),
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this)));
 
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 975b291..5c5058a 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -19,6 +20,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/ui/views/overlay/overlay_window_views.h"
@@ -26,6 +28,34 @@
 #include "ui/views/widget/widget_observer.h"
 #endif
 
+using ::testing::_;
+
+namespace {
+
+class MockPictureInPictureWindowController
+    : public content::PictureInPictureWindowController {
+ public:
+  MockPictureInPictureWindowController() = default;
+
+  // PictureInPictureWindowController:
+  MOCK_METHOD0(Show, gfx::Size());
+  MOCK_METHOD1(Close, void(bool));
+  MOCK_METHOD0(OnWindowDestroyed, void());
+  MOCK_METHOD1(ClickCustomControl, void(const std::string&));
+  MOCK_METHOD2(EmbedSurface, void(const viz::SurfaceId&, const gfx::Size&));
+  MOCK_METHOD0(GetWindowForTesting, content::OverlayWindow*());
+  MOCK_METHOD0(UpdateLayerBounds, void());
+  MOCK_METHOD0(IsPlayerActive, bool());
+  MOCK_METHOD0(GetInitiatorWebContents, content::WebContents*());
+  MOCK_METHOD2(UpdatePlaybackState, void(bool, bool));
+  MOCK_METHOD0(TogglePlayPause, bool());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockPictureInPictureWindowController);
+};
+
+}  // namespace
+
 class PictureInPictureWindowControllerBrowserTest
     : public InProcessBrowserTest {
  public:
@@ -47,6 +77,10 @@
     return pip_window_controller_;
   }
 
+  MockPictureInPictureWindowController& mock_controller() {
+    return mock_controller_;
+  }
+
   void LoadTabAndEnterPictureInPicture(Browser* browser) {
     GURL test_page_url = ui_test_utils::GetTestUrl(
         base::FilePath(base::FilePath::kCurrentDirectory),
@@ -95,6 +129,7 @@
 
  private:
   content::PictureInPictureWindowController* pip_window_controller_ = nullptr;
+  MockPictureInPictureWindowController mock_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(PictureInPictureWindowControllerBrowserTest);
 };
@@ -1003,4 +1038,107 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       EnterUsingControllerShowsWindow) {
+  auto* pip_window_manager = PictureInPictureWindowManager::GetInstance();
+  ASSERT_NE(nullptr, pip_window_manager);
+
+  // Show the non-WebContents based Picture-in-Picture window controller.
+  EXPECT_CALL(mock_controller(), Show());
+  pip_window_manager->EnterPictureInPictureWithController(&mock_controller());
+}
+
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       EnterUsingWebContentsThenUsingController) {
+  // Enter using WebContents.
+  LoadTabAndEnterPictureInPicture(browser());
+
+  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
+      window_controller()->GetWindowForTesting());
+  ASSERT_NE(nullptr, overlay_window);
+  EXPECT_TRUE(overlay_window->IsVisible());
+
+  auto* pip_window_manager = PictureInPictureWindowManager::GetInstance();
+  ASSERT_NE(nullptr, pip_window_manager);
+
+  // The new Picture-in-Picture window should be shown.
+  EXPECT_CALL(mock_controller(), Show());
+  pip_window_manager->EnterPictureInPictureWithController(&mock_controller());
+
+  // WebContents sourced Picture-in-Picture should stop.
+  bool in_picture_in_picture = false;
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(ExecuteScriptAndExtractBool(
+      active_web_contents, "isInPictureInPicture();", &in_picture_in_picture));
+  EXPECT_FALSE(in_picture_in_picture);
+
+  // TODO(edcourtney): When the renderer process is destroyed, it calls into
+  // MediaWebContentsObserver::ExitPictureInPictureInternal which Closes the
+  // current PIP. However, this may not be a WebContents sourced PIP, so this
+  // close can be spurious.
+  EXPECT_CALL(mock_controller(), Close(_));
+}
+
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       EnterUsingControllerThenEnterUsingWebContents) {
+  auto* pip_window_manager = PictureInPictureWindowManager::GetInstance();
+  ASSERT_NE(nullptr, pip_window_manager);
+
+  // Show the non-WebContents based Picture-in-Picture window controller.
+  EXPECT_CALL(mock_controller(), Show());
+  pip_window_manager->EnterPictureInPictureWithController(&mock_controller());
+
+  // Now show the WebContents based Picture-in-Picture window controller.
+  // This should close the existing window and show the new one.
+  EXPECT_CALL(mock_controller(), Close(_));
+  LoadTabAndEnterPictureInPicture(browser());
+
+  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
+      window_controller()->GetWindowForTesting());
+  ASSERT_TRUE(overlay_window);
+  EXPECT_TRUE(overlay_window->IsVisible());
+}
+
 #endif  // !defined(OS_ANDROID)
+
+// This checks that a video in Picture-in-Picture with preload none, when
+// changing source willproperly update the associated media player id. This is
+// checked by closing the window because the test it at a too high level to be
+// able to check the actual media player id being used.
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       PreloadNoneSrcChangeThenLoad) {
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(FILE_PATH_LITERAL(
+          "media/picture-in-picture/player_preload_none.html")));
+  ui_test_utils::NavigateToURL(browser(), test_page_url);
+
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(active_web_contents);
+
+  SetUpWindowController(active_web_contents);
+
+  bool result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(active_web_contents,
+                                                   "play();", &result));
+  ASSERT_TRUE(result);
+
+  result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      active_web_contents, "enterPictureInPicture();", &result));
+  ASSERT_TRUE(result);
+
+  result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      active_web_contents, "changeSrcAndLoad();", &result));
+  ASSERT_TRUE(result);
+
+  window_controller()->Close(true /* should_pause_video */);
+
+  result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      active_web_contents, "isInPictureInPicture();", &result));
+  EXPECT_FALSE(result);
+}
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
index f1270718..299757d 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
@@ -40,6 +40,18 @@
   return base::Singleton<PictureInPictureWindowManager>::get();
 }
 
+void PictureInPictureWindowManager::EnterPictureInPictureWithController(
+    content::PictureInPictureWindowController* pip_window_controller) {
+  // If there was already a controller, close the existing window before
+  // creating the next one.
+  if (pip_window_controller_)
+    CloseWindowInternal();
+
+  pip_window_controller_ = pip_window_controller;
+
+  pip_window_controller_->Show();
+}
+
 gfx::Size PictureInPictureWindowManager::EnterPictureInPicture(
     content::WebContents* web_contents,
     const viz::SurfaceId& surface_id,
@@ -49,9 +61,11 @@
   if (pip_window_controller_)
     CloseWindowInternal();
 
-  // Create or update |pip_window_controller_| for the current WebContents.
+  // Create or update |pip_window_controller_| for the current WebContents, if
+  // it is a WebContents based PIP.
   if (!pip_window_controller_ ||
-      pip_window_controller_->GetInitiatorWebContents() != web_contents) {
+      (pip_window_controller_->GetInitiatorWebContents() != nullptr &&
+       pip_window_controller_->GetInitiatorWebContents() != web_contents)) {
     CreateWindowInternal(web_contents);
   }
 
@@ -73,7 +87,6 @@
 }
 
 void PictureInPictureWindowManager::CloseWindowInternal() {
-  DCHECK(contents_observer_);
   DCHECK(pip_window_controller_);
 
   contents_observer_.reset();
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
index 12cb157f..0b544a53 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
@@ -29,6 +29,11 @@
   // Returns the singleton instance.
   static PictureInPictureWindowManager* GetInstance();
 
+  // Some PIP windows (e.g. from ARC) may not have a WebContents as the source
+  // of the PIP content. This function lets them provide their own window
+  // controller directly.
+  void EnterPictureInPictureWithController(
+      content::PictureInPictureWindowController* pip_window_controller);
   gfx::Size EnterPictureInPicture(content::WebContents*,
                                   const viz::SurfaceId&,
                                   const gfx::Size&);
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 01d92c0f..4da7559 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -47,9 +47,7 @@
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_pref_names.h"
 #include "chromeos/chromeos_pref_names.h"
-#include "components/drive/drive_pref_names.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
-#include "ui/chromeos/events/pref_names.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace {
@@ -750,12 +748,6 @@
     dom_distiller::prefs::kFontScale,
     dom_distiller::prefs::kReaderForAccessibility,
 
-// components/drive/drive_pref_names.h
-#if defined(OS_CHROMEOS)
-    drive::prefs::kDisableDrive, drive::prefs::kDisableDriveOverCellular,
-    drive::prefs::kDisableDriveHostedFiles,
-#endif  // defined(OS_CHROMEOS)
-
 // components/feed/core/pref_names.h
 #if defined(OS_ANDROID)
 #if BUILDFLAG(ENABLE_FEED_IN_CHROME)
@@ -852,14 +844,6 @@
     chromeos::extension_ime_util::kBrailleImeEngineId,
     chromeos::extension_ime_util::kArcImeLanguage,
 #endif  // defined(OS_CHROMEOS)
-
-// ui/chromeos/events/pref_names.h
-#if defined(OS_CHROMEOS)
-    prefs::kLanguageRemapCapsLockKeyTo, prefs::kLanguageRemapSearchKeyTo,
-    prefs::kLanguageRemapControlKeyTo, prefs::kLanguageRemapAltKeyTo,
-    prefs::kLanguageRemapEscapeKeyTo, prefs::kLanguageRemapBackspaceKeyTo,
-    prefs::kLanguageRemapDiamondKeyTo,
-#endif  // defined(OS_CHROMEOS)
 };
 
 }  // namespace
diff --git a/chrome/browser/printing/cloud_print/privet_traffic_detector.cc b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
index d241f91..5176dad 100644
--- a/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
+++ b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
@@ -14,8 +14,8 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/browser_process.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
@@ -80,8 +80,7 @@
 
 void PrivetTrafficDetector::Start() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::BindOnce(&PrivetTrafficDetector::ScheduleRestart,
@@ -90,8 +89,7 @@
 
 void PrivetTrafficDetector::Stop() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 void PrivetTrafficDetector::HandleConnectionChanged(
diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
index 0b301b2..6200888c 100644
--- a/chrome/browser/profiles/renderer_updater.cc
+++ b/chrome/browser/profiles/renderer_updater.cc
@@ -53,6 +53,15 @@
 RendererUpdater::RendererUpdater(Profile* profile) : profile_(profile) {
   signin_manager_ = SigninManagerFactory::GetForProfile(profile_);
   signin_manager_->AddObserver(this);
+  variations_http_header_provider_ =
+      variations::VariationsHttpHeaderProvider::GetInstance();
+  variations_http_header_provider_->AddObserver(this);
+  cached_variation_ids_header_ =
+      variations_http_header_provider_->GetClientDataHeader(
+          false /* is_signed_in */);
+  cached_variation_ids_header_signed_in_ =
+      variations_http_header_provider_->GetClientDataHeader(
+          true /* is_signed_in */);
 
   PrefService* pref_service = profile->GetPrefs();
   force_google_safesearch_.Init(prefs::kForceGoogleSafeSearch, pref_service);
@@ -81,6 +90,8 @@
 void RendererUpdater::Shutdown() {
   signin_manager_->RemoveObserver(this);
   signin_manager_ = nullptr;
+  variations_http_header_provider_->RemoveObserver(this);
+  variations_http_header_provider_ = nullptr;
 }
 
 void RendererUpdater::InitializeRenderer(
@@ -147,6 +158,14 @@
   UpdateAllRenderers();
 }
 
+void RendererUpdater::VariationIdsHeaderUpdated(
+    const std::string& variation_ids_header,
+    const std::string& variation_ids_header_signed_in) {
+  cached_variation_ids_header_ = variation_ids_header;
+  cached_variation_ids_header_signed_in_ = variation_ids_header_signed_in;
+  UpdateAllRenderers();
+}
+
 void RendererUpdater::UpdateAllRenderers() {
   auto renderer_configurations = GetRendererConfigurations();
   for (auto& renderer_configuration : renderer_configurations)
@@ -155,9 +174,11 @@
 
 void RendererUpdater::UpdateRenderer(
     chrome::mojom::RendererConfigurationAssociatedPtr* renderer_configuration) {
+  bool is_signed_in = signin_manager_->IsAuthenticated();
   (*renderer_configuration)
-      ->SetConfiguration(signin_manager_->IsAuthenticated(),
-                         force_google_safesearch_.GetValue(),
+      ->SetConfiguration(force_google_safesearch_.GetValue(),
                          force_youtube_restrict_.GetValue(),
-                         allowed_domains_for_apps_.GetValue());
+                         allowed_domains_for_apps_.GetValue(),
+                         is_signed_in ? cached_variation_ids_header_signed_in_
+                                      : cached_variation_ids_header_);
 }
diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
index 863ab90..06a8460 100644
--- a/chrome/browser/profiles/renderer_updater.h
+++ b/chrome/browser/profiles/renderer_updater.h
@@ -5,12 +5,15 @@
 #ifndef CHROME_BROWSER_PROFILES_RENDERER_UPDATER_H_
 #define CHROME_BROWSER_PROFILES_RENDERER_UPDATER_H_
 
+#include <string>
+
 #include "base/macros.h"
 #include "chrome/common/renderer_configuration.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_member.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "components/variations/variations_http_header_provider.h"
 
 class Profile;
 
@@ -19,8 +22,10 @@
 }
 
 // The RendererUpdater is responsible for updating renderers about state change.
-class RendererUpdater : public KeyedService,
-                        public SigninManagerBase::Observer {
+class RendererUpdater
+    : public KeyedService,
+      public SigninManagerBase::Observer,
+      public variations::VariationsHttpHeaderProvider::Observer {
  public:
   explicit RendererUpdater(Profile* profile);
   ~RendererUpdater() override;
@@ -42,6 +47,11 @@
   void GoogleSigninSucceeded(const AccountInfo& account_info) override;
   void GoogleSignedOut(const AccountInfo& account_info) override;
 
+  // VariationsHttpHeaderProvider::Observer:
+  void VariationIdsHeaderUpdated(
+      const std::string& variation_ids_header,
+      const std::string& variation_ids_header_signed_in) override;
+
   // Update all renderers due to a configuration change.
   void UpdateAllRenderers();
 
@@ -52,12 +62,16 @@
   Profile* profile_;
   PrefChangeRegistrar pref_change_registrar_;
   SigninManagerBase* signin_manager_;
+  variations::VariationsHttpHeaderProvider* variations_http_header_provider_;
 
   // Prefs that we sync to the renderers.
   BooleanPrefMember force_google_safesearch_;
   IntegerPrefMember force_youtube_restrict_;
   StringPrefMember allowed_domains_for_apps_;
 
+  std::string cached_variation_ids_header_;
+  std::string cached_variation_ids_header_signed_in_;
+
   DISALLOW_COPY_AND_ASSIGN(RendererUpdater);
 };
 
diff --git a/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.css b/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.css
index 78406965..612c5e4c 100644
--- a/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.css
+++ b/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.css
@@ -17,6 +17,7 @@
   max-height: 300px;
   overflow: auto;
   padding: 12px 64px 0 64px;
+  width: 640px;
 }
 
 .shadow {
diff --git a/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.js b/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.js
index 376e0e60..246c8a6 100644
--- a/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.js
+++ b/chrome/browser/resources/chromeos/arc_support/recommend_app_list_view.js
@@ -75,18 +75,27 @@
   return selectedPackages;
 }
 
-// Add the scrolling shadow effect.
-(function() {
-const shadowThreshold = 5;
-var doc = document;
-doc.getElementById('recommend-apps-container').onscroll = function() {
+function toggleScrollShadow(container) {
+  const shadowThreshold = 5;
+  var doc = document;
   doc.getElementById('scroll-top')
-      .classList[this.scrollTop > shadowThreshold ? 'add' : 'remove']('shadow');
+      .classList.toggle('shadow', container.scrollTop > shadowThreshold);
   doc.getElementById('scroll-bottom')
-      .classList
-          [this.scrollHeight - this.clientHeight - this.scrollTop <
-                   shadowThreshold ?
-               'remove' :
-               'add']('shadow');
-};
-})();
\ No newline at end of file
+      .classList.toggle(
+          'shadow',
+          container.scrollHeight - container.clientHeight -
+                  container.scrollTop >=
+              shadowThreshold);
+}
+
+// Add the scroll shadow effect. This contains two parts. First initialize the
+// effect after all the contents have been generated. Then attach it to the
+// onscroll event.
+function addScrollShadowEffect() {
+  var doc = document;
+  var container = doc.getElementById('recommend-apps-container');
+  toggleScrollShadow(container);
+  container.onscroll = function() {
+    toggleScrollShadow(this);
+  };
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
index 0ea8dad..5ca9076 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.html
@@ -130,6 +130,17 @@
     <button id="changeDisplayStyle"></button>
   </div>
 
+  <h2 class="i18n" msgid="options_developer_options" id="developerDescription">
+    Developer Options
+  </h2>
+  <div class="option" id="developerOption">
+    <input id="developerOptionCheckBox" type="checkbox" class="checkbox pref"
+           name="developerOptionCheckBox">
+    <label>
+      Enable developer option test.
+    </label>
+  </div>
+
   <div id="status" role="live" aria-live="assertive">
   </div>
 
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
index c3b158c..27519b1 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/options.js
@@ -88,6 +88,14 @@
     }
   });
 
+  chrome.commandLinePrivate.hasSwitch(
+      'enable-chromevox-developer-option', function(enable) {
+        if (!enable) {
+          $('developerDescription').hidden = true;
+          $('developerOption').hidden = true;
+        }
+      });
+
   Msgs.addTranslatedMessagesToDom(document);
   cvox.OptionsPage.hidePlatformSpecifics();
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html
index 3d75bd4..feca3b8 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.html
@@ -1,9 +1,11 @@
 <!-- Components to load uncompressed ChromeVox -->
-<script src="../../closure/base.js"></script>
-<script src="../../deps.js"></script>
+<!--
+  <script src="../../closure/base.js"></script>
+  <script src="../../deps.js"></script>
+-->
 
 <!-- ChromeVox Next -->
-<script src="loader.js"></script>
+<!-- <script src="loader.js"></script> -->
 <script src="../../chromeVox2ChromeBackgroundScript.js"></script>
 
 <!-- Third party -->
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index bd4de2e..195df15 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -559,6 +559,9 @@
       <message desc="An option for setting the key combination that will be used as the ChromeVox modifier key (aka, the 'Cvox' key)." name="IDS_CHROMEVOX_OPTIONS_CVOX_MODIFIER_KEY">
         ChromeVox modifier key
       </message>
+      <message desc="List of chromevox developer options." name="IDS_CHROMEVOX_OPTIONS_DEVELOPER_OPTIONS">
+        Developer Options
+      </message>
       <message desc="The title of ChromeVox Learn Mode page.  The keyboard explorer voices the name of each key when the user presses it." name="IDS_CHROMEVOX_KBEXPLORER_TITLE">
         ChromeVox Learn Mode
       </message>
diff --git a/chrome/browser/resources/chromeos/login/screen_recommend_apps.js b/chrome/browser/resources/chromeos/login/screen_recommend_apps.js
index 3e8b8fb..5e0c2a8 100644
--- a/chrome/browser/resources/chromeos/login/screen_recommend_apps.js
+++ b/chrome/browser/resources/chromeos/login/screen_recommend_apps.js
@@ -102,6 +102,8 @@
             var generateContents = {code: generateItemScript};
             appListView.executeScript(generateContents);
           });
+          var addScrollShadowEffectScript = 'addScrollShadowEffect();';
+          appListView.executeScript({code: addScrollShadowEffectScript});
 
           this.onGenerateContents();
         });
diff --git a/chrome/browser/resources/discards/discards.js b/chrome/browser/resources/discards/discards.js
index aa3fbc1..d9b3c13 100644
--- a/chrome/browser/resources/discards/discards.js
+++ b/chrome/browser/resources/discards/discards.js
@@ -351,9 +351,10 @@
         boolToString(info.canFreeze);
     row.querySelector('.can-discard-div').textContent =
         boolToString(info.canDiscard);
-    // The lifecycle state is meaningless for 'unloaded' tabs.
+    // The lifecycle state is meaningless for tabs that have never been loaded.
     row.querySelector('.state-cell').textContent =
-        (info.loadingState != mojom.LifecycleUnitLoadingState.UNLOADED) ?
+        (info.loadingState != mojom.LifecycleUnitLoadingState.UNLOADED ||
+         info.discardCount > 0) ?
         lifecycleStateToString(info.state) :
         '';
     row.querySelector('.discard-count-cell').textContent =
@@ -371,9 +372,11 @@
 
     row.querySelector('.is-auto-discardable-link').removeAttribute('disabled');
     setActionLinkEnabled(
-        row.querySelector('.can-freeze-link'), !info.canFreeze);
+        row.querySelector('.can-freeze-link'),
+        (!info.canFreeze && info.cannotFreezeReasons.length > 0));
     setActionLinkEnabled(
-        row.querySelector('.can-discard-link'), !info.canDiscard);
+        row.querySelector('.can-discard-link'),
+        (!info.canDiscard && info.cannotDiscardReasons.length > 0));
     let loadLink = row.querySelector('.load-link');
     let freezeLink = row.querySelector('.freeze-link');
     let discardLink = row.querySelector('.discard-link');
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 6ab3fa9..d1beddaa 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -433,6 +433,7 @@
   display: flex;
   flex-flow: column nowrap;
   height: 100%;
+  position: relative;
   width: 100%;
   z-index: -1;
 }
diff --git a/chrome/browser/resources/settings/multidevice_page/BUILD.gn b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
index 43db27b..49e73d9 100644
--- a/chrome/browser/resources/settings/multidevice_page/BUILD.gn
+++ b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
@@ -61,6 +61,7 @@
 
 js_library("multidevice_subpage") {
   deps = [
+    ":multidevice_constants",
     "..:route",
     "../prefs:prefs_behavior",
     "//ui/webui/resources/js:i18n_behavior",
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_feature_item.html b/chrome/browser/resources/settings/multidevice_page/multidevice_feature_item.html
index f97c9047..3a79427 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_feature_item.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_feature_item.html
@@ -19,7 +19,8 @@
         padding-inline-start: 18px;
       }
     </style>
-    <div class="settings-box two-line"
+    <div id="card"
+        class="settings-box two-line"
         on-click="handleItemClick_"
         actionable$="[[hasSubpageClickHandler_(subpageRoute)]]">
       <iron-icon icon="[[iconName]]"></iron-icon>
@@ -37,7 +38,7 @@
         </paper-icon-button-light>
         <div class="separator"></div>
       </template>
-      <slot name="feature-contoller"></slot>
+      <slot name="feature-controller"></slot>
     </div>
   </template>
   <script src="multidevice_feature_item.js"></script>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
index 804ffe8..79e86fc 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
@@ -8,6 +8,7 @@
 <link rel="import" href="../route.html">
 <link rel="import" href="../settings_shared_css.html">
 <link rel="import" href="../settings_vars_css.html">
+<link rel="import" href="multidevice_constants.html">
 <link rel="import" href="multidevice_feature_item.html">
 <link rel="import" href="multidevice_feature_toggle.html">
 
@@ -36,7 +37,8 @@
         if="[[shouldShowIndividualFeatures_(pageContentData)]]"
         restamp>
       <div class="feature-item-container">
-        <settings-multidevice-feature-item icon-name="settings:smart-lock"
+        <settings-multidevice-feature-item id="smart-lock-item"
+            icon-name="settings:smart-lock"
             subpage-route="[[routes.LOCK_SCREEN]]"
             feature-name="$i18n{multideviceSmartLockItemTitle}"
             feature-summary-html="$i18n{multideviceSmartLockItemSummary}">
@@ -49,16 +51,21 @@
             </settings-multidevice-feature-toggle>
           </div>
         </settings-multidevice-feature-item>
-        <settings-multidevice-feature-item icon-name="settings:sms-connect"
+        <settings-multidevice-feature-item id="android-messages-item"
+            icon-name="settings:sms-connect"
             feature-name="$i18n{multideviceAndroidMessagesItemTitle}"
             feature-summary-html="$i18n{multideviceAndroidMessagesItemSummary}">
-          <div slot="feature-contoller">
-            <template is="dom-if" if="[[androidMessagesRequiresSetup_]]">
+          <div slot="feature-controller">
+            <template is="dom-if"
+                if="[[androidMessagesRequiresSetup_]]"
+                restamp>
               <paper-button on-click="handleAndroidMessagesButtonClick_">
                 $i18n{multideviceSetupButton}
               </paper-button>
             </template>
-            <template is="dom-if" if="[[!androidMessagesRequiresSetup_]]">
+            <template is="dom-if"
+                if="[[!androidMessagesRequiresSetup_]]"
+                restamp>
               <settings-multidevice-feature-toggle
                   pref="{{prefs.multidevice.sms_connect_enabled}}">
               </settings-multidevice-feature-toggle>
diff --git a/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc b/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc
index 98657a5..88f6736 100644
--- a/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc
@@ -291,13 +291,6 @@
                                   DownloadCheckResult response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DVLOG(2) << __func__ << " response: " << static_cast<int>(response);
-  base::UmaHistogramSparse(
-      "SBClientDownload.PPAPIDownloadRequest.RequestOutcome",
-      static_cast<int>(reason));
-  base::UmaHistogramSparse("SBClientDownload.PPAPIDownloadRequest.Result",
-                           static_cast<int>(response));
-  UMA_HISTOGRAM_TIMES("SBClientDownload.PPAPIDownloadRequest.RequestDuration",
-                      base::TimeTicks::Now() - start_time_);
   if (!callback_.is_null())
     base::ResetAndReturn(&callback_).Run(response);
   loader_.reset();
diff --git a/chrome/browser/sessions/tab_loader_delegate.cc b/chrome/browser/sessions/tab_loader_delegate.cc
index 4c6bb81b..4cbaa52 100644
--- a/chrome/browser/sessions/tab_loader_delegate.cc
+++ b/chrome/browser/sessions/tab_loader_delegate.cc
@@ -7,11 +7,11 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/session_restore_policy.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/sessions/session_restore_observer.h"
 #include "components/variations/variations_associated_data.h"
+#include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 
 namespace {
@@ -79,10 +79,9 @@
 
 TabLoaderDelegateImpl::TabLoaderDelegateImpl(TabLoaderCallback* callback)
     : callback_(callback), weak_factory_(this) {
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
   auto type = network::mojom::ConnectionType::CONNECTION_UNKNOWN;
-  g_browser_process->network_connection_tracker()->GetConnectionType(
+  content::GetNetworkConnectionTracker()->GetConnectionType(
       &type, base::BindOnce(&TabLoaderDelegateImpl::OnConnectionChanged,
                             weak_factory_.GetWeakPtr()));
   if (type == network::mojom::ConnectionType::CONNECTION_NONE) {
@@ -98,8 +97,7 @@
 }
 
 TabLoaderDelegateImpl::~TabLoaderDelegateImpl() {
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 void TabLoaderDelegateImpl::OnConnectionChanged(
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 4aa7746..d726bff 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -44,6 +44,7 @@
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/signin/core/browser/signin_switches.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -79,8 +80,7 @@
       weak_ptr_factory_(this) {
   signin_error_controller_->AddObserver(this);
 #if !defined(OS_CHROMEOS)
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 #else
   // UserManager may not exist in unit_tests.
   if (!user_manager::UserManager::IsInitialized())
@@ -113,8 +113,7 @@
 ChromeSigninClient::~ChromeSigninClient() {
   signin_error_controller_->RemoveObserver(this);
 #if !defined(OS_CHROMEOS)
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 #endif
 }
 
@@ -398,10 +397,9 @@
 #else
   // Don't bother if we don't have any kind of network connection.
   network::mojom::ConnectionType type;
-  bool sync =
-      g_browser_process->network_connection_tracker()->GetConnectionType(
-          &type, base::BindOnce(&ChromeSigninClient::OnConnectionChanged,
-                                weak_ptr_factory_.GetWeakPtr()));
+  bool sync = content::GetNetworkConnectionTracker()->GetConnectionType(
+      &type, base::BindOnce(&ChromeSigninClient::OnConnectionChanged,
+                            weak_ptr_factory_.GetWeakPtr()));
   if (!sync || type == network::mojom::ConnectionType::CONNECTION_NONE) {
     // Connection type cannot be retrieved synchronously so delay the callback.
     delayed_callbacks_.push_back(callback);
diff --git a/chrome/browser/signin/chrome_signin_client_unittest.cc b/chrome/browser/signin/chrome_signin_client_unittest.cc
index e39a4fef..0fa3d156 100644
--- a/chrome/browser/signin/chrome_signin_client_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_client_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/signin/core/browser/profile_management_switches.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/test/test_network_connection_tracker.h"
@@ -63,8 +64,9 @@
   ChromeSigninClientTest() {}
 
   void Initialize(std::unique_ptr<network::NetworkConnectionTracker> tracker) {
-    TestingBrowserProcess::GetGlobal()->SetNetworkConnectionTracker(
-        std::move(tracker));
+    network_connection_tracker_ = std::move(tracker);
+    content::SetNetworkConnectionTrackerForTesting(
+        network_connection_tracker_.get());
     // Create a signed-in profile.
     TestingProfile::Builder builder;
     profile_ = builder.Build();
@@ -77,6 +79,8 @@
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<network::NetworkConnectionTracker>
+      network_connection_tracker_;
   std::unique_ptr<Profile> profile_;
   SigninClient* signin_client_;
 };
diff --git a/chrome/browser/signin/force_signin_verifier.cc b/chrome/browser/signin/force_signin_verifier.cc
index 383e375..ff6de48 100644
--- a/chrome/browser/signin/force_signin_verifier.cc
+++ b/chrome/browser/signin/force_signin_verifier.cc
@@ -8,11 +8,11 @@
 
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "content/public/browser/network_service_instance.h"
 #include "google_apis/gaia/gaia_constants.h"
 
 namespace {
@@ -44,8 +44,7 @@
       oauth2_token_service_(
           ProfileOAuth2TokenServiceFactory::GetForProfile(profile)),
       signin_manager_(SigninManagerFactory::GetForProfile(profile)) {
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
   UMA_HISTOGRAM_BOOLEAN(kForceSigninVerificationMetricsName,
                         ShouldSendRequest());
   SendRequest();
@@ -62,8 +61,7 @@
   UMA_HISTOGRAM_MEDIUM_TIMES(kForceSigninVerificationSuccessTimeMetricsName,
                              base::TimeTicks::Now() - creation_time_);
   has_token_verified_ = true;
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
   Cancel();
 }
 
@@ -75,8 +73,8 @@
                                base::TimeTicks::Now() - creation_time_);
     has_token_verified_ = true;
     CloseAllBrowserWindows();
-    g_browser_process->network_connection_tracker()
-        ->RemoveNetworkConnectionObserver(this);
+    content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(
+        this);
     Cancel();
   } else {
     backoff_entry_.InformOfRequest(false);
@@ -103,8 +101,7 @@
   backoff_entry_.Reset();
   backoff_request_timer_.Stop();
   access_token_request_.reset();
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 bool ForceSigninVerifier::HasTokenBeenVerified() {
@@ -124,8 +121,8 @@
 
 bool ForceSigninVerifier::ShouldSendRequest() {
   auto type = network::mojom::ConnectionType::CONNECTION_NONE;
-  g_browser_process->network_connection_tracker()->GetConnectionType(
-      &type, base::DoNothing());
+  content::GetNetworkConnectionTracker()->GetConnectionType(&type,
+                                                            base::DoNothing());
   return !has_token_verified_ && access_token_request_.get() == nullptr &&
          type != network::mojom::ConnectionType::CONNECTION_NONE &&
          signin_manager_->IsAuthenticated();
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
index adb742f..8b2abb13 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -14,7 +14,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_client.h"
@@ -22,6 +21,7 @@
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/signin/core/browser/webdata/token_web_data.h"
 #include "components/webdata/common/web_data_service_base.h"
+#include "content/public/browser/network_service_instance.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -359,8 +359,7 @@
   backoff_policy_.maximum_backoff_ms = 15 * 60 * 1000;
   backoff_policy_.entry_lifetime_ms = -1;
   backoff_policy_.always_use_initial_delay = false;
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 
 #if !defined(OS_CHROMEOS)
   // Ensure the device ID is not empty.
@@ -373,8 +372,7 @@
     ~MutableProfileOAuth2TokenServiceDelegate() {
   VLOG(1) << "MutablePO2TS::~MutablePO2TS";
   DCHECK(server_revokes_.empty());
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
 }
 
 // static
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
index c87d0e33..ab1d039d 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -11,7 +11,6 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -28,6 +27,7 @@
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/signin/core/browser/webdata/token_web_data.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -121,6 +121,7 @@
   }
 
   void TearDown() override {
+    base::RunLoop().RunUntilIdle();
     oauth2_service_delegate_->RemoveObserver(this);
     oauth2_service_delegate_->Shutdown();
     OSCryptMocker::TearDown();
@@ -216,7 +217,7 @@
   }
 
  protected:
-  base::MessageLoop message_loop_;
+  content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<TestSigninClient> client_;
   std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate>
       oauth2_service_delegate_;
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc
index 92188d7..32172f5 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.cc
+++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -110,6 +110,14 @@
   return entries;
 }
 
+void SetServerCardsOnDBSequence(
+    AutofillWebDataService* wds,
+    const std::vector<autofill::CreditCard>& credit_cards) {
+  DCHECK(wds->GetDBTaskRunner()->RunsTasksInCurrentSequence());
+  AutofillTable::FromWebDatabase(wds->GetDatabase())
+      ->SetServerCreditCards(credit_cards);
+}
+
 bool ProfilesMatchImpl(
     int profile_a,
     const std::vector<AutofillProfile*>& autofill_profiles_a,
@@ -284,6 +292,16 @@
   GetPersonalDataManager(profile)->SetCreditCards(credit_cards);
 }
 
+void SetServerCreditCards(
+    int profile,
+    const std::vector<autofill::CreditCard>& credit_cards) {
+  scoped_refptr<AutofillWebDataService> wds = GetProfileWebDataService(profile);
+  wds->GetDBTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&SetServerCardsOnDBSequence,
+                                base::Unretained(wds.get()), credit_cards));
+  WaitForCurrentTasksToComplete(wds->GetDBTaskRunner());
+}
+
 void AddProfile(int profile, const AutofillProfile& autofill_profile) {
   std::vector<AutofillProfile> autofill_profiles;
   for (AutofillProfile* profile : GetAllAutoFillProfiles(profile)) {
diff --git a/chrome/browser/sync/test/integration/autofill_helper.h b/chrome/browser/sync/test/integration/autofill_helper.h
index 241d61d0..199977b0 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.h
+++ b/chrome/browser/sync/test/integration/autofill_helper.h
@@ -75,6 +75,10 @@
 void SetCreditCards(int profile,
                     std::vector<autofill::CreditCard>* credit_cards);
 
+void SetServerCreditCards(
+    int profile,
+    const std::vector<autofill::CreditCard>& credit_cards);
+
 // Adds the autofill profile |autofill_profile| to sync profile |profile|.
 void AddProfile(int profile, const autofill::AutofillProfile& autofill_profile);
 
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 79454e6d..1fb1af2 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -4,6 +4,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/sync/test/integration/autofill_helper.h"
@@ -15,6 +16,7 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -24,20 +26,29 @@
 #include "components/sync/test/fake_server/fake_server.h"
 #include "components/webdata/common/web_data_service_consumer.h"
 #include "content/public/browser/notification_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
+using autofill::CreditCard;
 using autofill_helper::GetPersonalDataManager;
 using autofill_helper::GetProfileWebDataService;
 using autofill_helper::GetAccountWebDataService;
 
 namespace {
 
+ACTION_P(QuitMessageLoop, loop) {
+  loop->Quit();
+}
+
 const char kDefaultCardID[] = "wallet entity ID";
 const int kDefaultCardExpMonth = 8;
 const int kDefaultCardExpYear = 2087;
 const char kDefaultCardLastFour[] = "1234";
 const char kDefaultCardName[] = "Patrick Valenzuela";
+const char kDefaultBillingAddressId[] = "address entity ID";
 const sync_pb::WalletMaskedCreditCard_WalletCardType kDefaultCardType =
     sync_pb::WalletMaskedCreditCard::AMEX;
+const char kLocalGuidA[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A";
+const char kDifferentBillingAddressId[] = "another address entity ID";
 
 template <class T>
 class AutofillWebDataServiceConsumer : public WebDataServiceConsumer {
@@ -63,10 +74,18 @@
   DISALLOW_COPY_AND_ASSIGN(AutofillWebDataServiceConsumer);
 };
 
-std::vector<std::unique_ptr<autofill::CreditCard>> GetServerCards(
+class PersonalDataLoadedObserverMock
+    : public autofill::PersonalDataManagerObserver {
+ public:
+  PersonalDataLoadedObserverMock() {}
+  ~PersonalDataLoadedObserverMock() override {}
+
+  MOCK_METHOD0(OnPersonalDataChanged, void());
+};
+
+std::vector<std::unique_ptr<CreditCard>> GetServerCards(
     scoped_refptr<autofill::AutofillWebDataService> service) {
-  AutofillWebDataServiceConsumer<
-      std::vector<std::unique_ptr<autofill::CreditCard>>>
+  AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
       consumer;
   service->GetServerCreditCards(&consumer);
   consumer.Wait();
@@ -89,12 +108,27 @@
   credit_card->set_name_on_card(kDefaultCardName);
   credit_card->set_status(sync_pb::WalletMaskedCreditCard::VALID);
   credit_card->set_type(kDefaultCardType);
+  credit_card->set_billing_address_id(kDefaultBillingAddressId);
 
   server->InjectEntity(
       syncer::PersistentUniqueClientEntity::CreateFromEntitySpecifics(
           kDefaultCardID, specifics, 12345, 12345));
 }
 
+CreditCard GetDefaultCreditCard() {
+  CreditCard card(CreditCard::MASKED_SERVER_CARD, kDefaultCardID);
+  card.SetExpirationMonth(kDefaultCardExpMonth);
+  card.SetExpirationYear(kDefaultCardExpYear);
+  card.SetNumber(base::UTF8ToUTF16(kDefaultCardLastFour));
+  card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL,
+                  base::UTF8ToUTF16(kDefaultCardName));
+  card.SetServerStatus(CreditCard::OK);
+  card.SetNetworkForMaskedCard(autofill::kAmericanExpressCard);
+  card.set_card_type(CreditCard::CARD_TYPE_CREDIT);
+  card.set_billing_address_id(kDefaultBillingAddressId);
+  return card;
+}
+
 }  // namespace
 
 class SingleClientWalletSyncTest : public SyncTest {
@@ -102,6 +136,20 @@
   SingleClientWalletSyncTest() : SyncTest(SINGLE_CLIENT) {}
   ~SingleClientWalletSyncTest() override {}
 
+ protected:
+  void RefreshAndWaitForOnPersonalDataChanged(
+      autofill::PersonalDataManager* pdm) {
+    pdm->AddObserver(&personal_data_observer_);
+    pdm->Refresh();
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .WillRepeatedly(QuitMessageLoop(&run_loop));
+    run_loop.Run();
+    pdm->RemoveObserver(&personal_data_observer_);
+  }
+
+  PersonalDataLoadedObserverMock personal_data_observer_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SingleClientWalletSyncTest);
 };
@@ -143,7 +191,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, EnabledByDefault) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_DATA));
   // TODO(pvalenzuela): Assert that the local root node for AUTOFILL_WALLET_DATA
@@ -160,7 +208,7 @@
       // Disabled.
       {autofill::features::kAutofillEnableAccountWalletStorage});
   AddDefaultCard(GetFakeServer());
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(SetupSync());
 
   auto profile_data = GetProfileWebDataService(0);
   ASSERT_NE(nullptr, profile_data);
@@ -169,11 +217,11 @@
 
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
-  autofill::CreditCard* card = cards[0];
-  EXPECT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
+  CreditCard* card = cards[0];
+  EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type());
   EXPECT_EQ(kDefaultCardID, card->server_id());
   EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
   EXPECT_EQ(autofill::kAmericanExpressCard, card->network());
@@ -181,6 +229,7 @@
   EXPECT_EQ(kDefaultCardExpYear, card->expiration_year());
   EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardName),
             card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(kDefaultBillingAddressId, card->billing_address_id());
 
   // Check that the card is stored in the profile storage.
   EXPECT_EQ(1U, GetServerCards(GetProfileWebDataService(0)).size());
@@ -203,6 +252,7 @@
 
   ASSERT_TRUE(SetupClients());
   AddDefaultCard(GetFakeServer());
+
   ASSERT_TRUE(GetClient(0)->SignIn());
   ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization(
       /*skip_passphrase_verification=*/false));
@@ -225,11 +275,11 @@
 
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
-  autofill::CreditCard* card = cards[0];
-  EXPECT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
+  CreditCard* card = cards[0];
+  EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, card->record_type());
   EXPECT_EQ(kDefaultCardID, card->server_id());
   EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
   EXPECT_EQ(autofill::kAmericanExpressCard, card->network());
@@ -237,18 +287,19 @@
   EXPECT_EQ(kDefaultCardExpYear, card->expiration_year());
   EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardName),
             card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(kDefaultBillingAddressId, card->billing_address_id());
 }
 #endif  // !defined(OS_CHROMEOS)
 
 // Wallet data should get cleared from the database when sync is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableSync) {
   AddDefaultCard(GetFakeServer());
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
   // Turn off sync, the card should be gone.
@@ -261,12 +312,12 @@
 // flag is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableWalletSync) {
   AddDefaultCard(GetFakeServer());
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
   // Turn off autofill sync, the card should be gone.
@@ -280,12 +331,12 @@
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        ClearOnDisableWalletAutofill) {
   AddDefaultCard(GetFakeServer());
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(SetupSync());
 
   // Make sure the card is in the DB.
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
-  std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
 
   // Turn off the wallet autofill pref, the card should be gone as a side
@@ -295,3 +346,104 @@
   cards = pdm->GetCreditCards();
   ASSERT_EQ(0uL, cards.size());
 }
+
+// Wallet data present on the client should be cleared in favor of the new data
+// synced down form the server.
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       NewWalletCardRemovesExistingCard) {
+  ASSERT_TRUE(SetupClients());
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+
+  // Add a server credit card on the client.
+  CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
+  std::vector<CreditCard> credit_cards = {credit_card};
+  autofill_helper::SetServerCreditCards(0, credit_cards);
+
+  // Refresh the pdm so that it gets cards from autofill table.
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Make sure the card was added correctly.
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ("a123", cards[0]->server_id());
+
+  // Add a new card from the server and sync it down.
+  AddDefaultCard(GetFakeServer());
+  ASSERT_TRUE(SetupSync());
+
+  // The only card present on the client should be the one from the server.
+  cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(kDefaultCardID, cards[0]->server_id());
+}
+
+// Tests that a local billing address id set on a card on the client should not
+// be overwritten when that same card is synced again.
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       SameWalletCard_PreservesLocalBillingAddressId) {
+  ASSERT_TRUE(SetupClients());
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+
+  // Add a server credit card on the client but with the billing address id of a
+  // local profile.
+  CreditCard credit_card = GetDefaultCreditCard();
+  credit_card.set_billing_address_id(kLocalGuidA);
+  std::vector<CreditCard> credit_cards = {credit_card};
+  autofill_helper::SetServerCreditCards(0, credit_cards);
+
+  // Refresh the pdm so that it gets cards from autofill table.
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Make sure the card was added correctly.
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(kDefaultCardID, cards[0]->server_id());
+
+  // Sync the same card from the server, except with a default billing address
+  // id.
+  AddDefaultCard(GetFakeServer());
+  ASSERT_TRUE(SetupSync());
+
+  // The billing address is should still refer to the local profile.
+  cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(kDefaultCardID, cards[0]->server_id());
+  EXPECT_EQ(kLocalGuidA, cards[0]->billing_address_id());
+}
+
+// Tests that a server billing address id set on a card on the client is
+// overwritten when that same card is synced again.
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       SameWalletCard_DiscardsOldServerBillingAddressId) {
+  ASSERT_TRUE(SetupClients());
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+
+  // Add a server credit card on the client but with the billing address id of a
+  // server profile.
+  CreditCard credit_card = GetDefaultCreditCard();
+  credit_card.set_billing_address_id(kDifferentBillingAddressId);
+  std::vector<CreditCard> credit_cards = {credit_card};
+  autofill_helper::SetServerCreditCards(0, credit_cards);
+
+  // Refresh the pdm so that it gets cards from autofill table.
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Make sure the card was added correctly.
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(kDefaultCardID, cards[0]->server_id());
+
+  // Sync the same card from the server, except with a default billing address
+  // id.
+  AddDefaultCard(GetFakeServer());
+  ASSERT_TRUE(SetupSync());
+
+  // The billing address should be the one from the server card.
+  cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(kDefaultCardID, cards[0]->server_id());
+  EXPECT_EQ(kDefaultBillingAddressId, cards[0]->billing_address_id());
+}
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index 056df0ca..0412945 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -72,7 +72,7 @@
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        PersonalDataManagerSanity) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Client0 adds a profile.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
@@ -109,18 +109,18 @@
 }
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, AddDuplicateProfiles) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(SetupClients());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
 }
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        SameProfileWithConflict) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(SetupClients());
 
   AutofillProfile profile0 = CreateAutofillProfile(PROFILE_HOMER);
   AutofillProfile profile1 = CreateAutofillProfile(PROFILE_HOMER);
@@ -129,14 +129,14 @@
 
   AddProfile(0, profile0);
   AddProfile(1, profile1);
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
 }
 
 // Tests that a null profile does not get synced across clients.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, AddEmptyProfile) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_NULL));
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -146,7 +146,7 @@
 // Tests that adding a profile on one client results in it being added on the
 // other client when sync is running.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, AddProfile) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
 
@@ -166,7 +166,7 @@
 
   // Add the new autofill profile before starting sync.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Wait for the sync to happen.
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -191,7 +191,7 @@
             GetAllAutoFillProfiles(1)[0]->guid());
 
   // Wait for the sync to happen.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
   // Make sure that both clients have one profile.
@@ -207,12 +207,12 @@
 // being added to the other client.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        AddMultipleProfilesOnOneClient) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(SetupClients());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   AddProfile(0, CreateAutofillProfile(PROFILE_MARION));
   AddProfile(0, CreateAutofillProfile(PROFILE_FRASIER));
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
   EXPECT_EQ(3U, GetAllAutoFillProfiles(0).size());
 }
@@ -221,12 +221,12 @@
 // all profiles.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        AddMultipleProfilesOnTwoClients) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(SetupClients());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   AddProfile(1, CreateAutofillProfile(PROFILE_MARION));
   AddProfile(1, CreateAutofillProfile(PROFILE_FRASIER));
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
   EXPECT_EQ(3U, GetAllAutoFillProfiles(0).size());
 }
@@ -234,7 +234,7 @@
 // Tests that deleting a profile on one client results in it being deleted on
 // the other client.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, DeleteProfile) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Setup the test by making the 2 clients have the same profile.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
@@ -252,7 +252,7 @@
 // Tests that modifying a profile while syncing results in the other client
 // getting the updated profile.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, UpdateFields) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -284,7 +284,7 @@
 // which one).
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        UpdateConflictingFields) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Make the two clients have the same profile.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
@@ -309,7 +309,7 @@
 // which one).
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        UpdateConflictingFieldsDuringInitialMerge) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_TRUE(SetupClients());
 
   // Make the two clients have the same profile.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
@@ -322,7 +322,7 @@
                 AutofillType(autofill::NAME_FIRST), base::ASCIIToUTF16("Bart"));
 
   // Start sync.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Don't care which write wins the conflict, only that the two clients agree.
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -333,7 +333,7 @@
 // syncing results in both client having the same profile (doesn't matter which
 // one).
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, DeleteAndUpdate) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // Make the two clients have the same profile.
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
@@ -353,7 +353,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, MaxLength) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   ASSERT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -377,7 +377,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, ExceedsMaxLength) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   ASSERT_TRUE(AutofillProfileChecker(0, 1).Wait());
@@ -408,7 +408,7 @@
 
 // Test credit cards don't sync.
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest, NoCreditCardSync) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   CreditCard card;
   card.SetRawInfo(autofill::CREDIT_CARD_NUMBER,
@@ -431,7 +431,7 @@
 
 IN_PROC_BROWSER_TEST_P(TwoClientAutofillProfileSyncTest,
                        E2E_ONLY(TwoClientsAddAutofillProfiles)) {
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(SetupSync());
 
   // All profiles should sync same autofill profiles.
   ASSERT_TRUE(AutofillProfileChecker(0, 1).Wait())
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
index ffb8d9c..27a6ba99 100644
--- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -1680,7 +1680,7 @@
 
 // Test a scenario of updating the name of the same bookmark from two clients at
 // the same time.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        MC_BookmarkNameChangeConflict) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -1705,7 +1705,7 @@
 
 // Test a scenario of updating the URL of the same bookmark from two clients at
 // the same time.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        MC_BookmarkURLChangeConflict) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -1732,7 +1732,7 @@
 
 // Test a scenario of updating the BM Folder name from two clients at the same
 // time.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        MC_FolderNameChangeConflict) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
   DisableVerifier();
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
index 8228ee8..6eb3ed5 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
@@ -14,7 +14,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -50,6 +49,7 @@
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/extension_system.h"
@@ -249,8 +249,7 @@
 SyncEngine::~SyncEngine() {
   Reset();
 
-  g_browser_process->network_connection_tracker()
-      ->RemoveNetworkConnectionObserver(this);
+  content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
   if (signin_manager_)
     signin_manager_->RemoveObserver(this);
   if (notification_manager_)
@@ -370,7 +369,7 @@
 
   service_state_ = REMOTE_SERVICE_TEMPORARY_UNAVAILABLE;
   auto connection_type = network::mojom::ConnectionType::CONNECTION_NONE;
-  g_browser_process->network_connection_tracker()->GetConnectionType(
+  content::GetNetworkConnectionTracker()->GetConnectionType(
       &connection_type, base::BindOnce(&SyncEngine::OnConnectionChanged,
                                        weak_ptr_factory_.GetWeakPtr()));
   OnConnectionChanged(connection_type);
@@ -764,8 +763,7 @@
     notification_manager_->AddObserver(this);
   if (signin_manager_)
     signin_manager_->AddObserver(this);
-  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
-      this);
+  content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 }
 
 void SyncEngine::OnPendingFileListUpdated(int item_count) {
diff --git a/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc b/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc
index 20818232..312b76a0 100644
--- a/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc
+++ b/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc
@@ -437,13 +437,12 @@
 }
 
 int64_t CannedSyncableFileSystem::Write(
-    net::URLRequestContext* url_request_context,
     const FileSystemURL& url,
     std::unique_ptr<storage::BlobDataHandle> blob_data_handle) {
   return RunOnThread<int64_t>(
       io_task_runner_.get(), FROM_HERE,
       base::BindOnce(&CannedSyncableFileSystem::DoWrite, base::Unretained(this),
-                     url_request_context, url, std::move(blob_data_handle)));
+                     url, std::move(blob_data_handle)));
 }
 
 int64_t CannedSyncableFileSystem::WriteString(const FileSystemURL& url,
@@ -636,7 +635,6 @@
 }
 
 void CannedSyncableFileSystem::DoWrite(
-    net::URLRequestContext* url_request_context,
     const FileSystemURL& url,
     std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
     const WriteCallback& callback) {
@@ -644,7 +642,7 @@
   EXPECT_TRUE(is_filesystem_opened_);
   WriteHelper* helper = new WriteHelper;
   operation_runner()->Write(
-      url_request_context, url, std::move(blob_data_handle), 0,
+      url, std::move(blob_data_handle), 0,
       base::Bind(&WriteHelper::DidWrite, base::Owned(helper), callback));
 }
 
@@ -657,10 +655,10 @@
   MockBlobURLRequestContext* url_request_context(
       new MockBlobURLRequestContext());
   WriteHelper* helper = new WriteHelper(url_request_context, data);
-  operation_runner()->Write(url_request_context, url,
+  operation_runner()->Write(url,
                             helper->scoped_text_blob()->GetBlobDataHandle(), 0,
-                            base::Bind(&WriteHelper::DidWrite,
-                                       base::Owned(helper), callback));
+                            base::BindRepeating(&WriteHelper::DidWrite,
+                                                base::Owned(helper), callback));
 }
 
 void CannedSyncableFileSystem::DoGetUsageAndQuota(
diff --git a/chrome/browser/sync_file_system/local/canned_syncable_file_system.h b/chrome/browser/sync_file_system/local/canned_syncable_file_system.h
index 03bee0b..16635ed 100644
--- a/chrome/browser/sync_file_system/local/canned_syncable_file_system.h
+++ b/chrome/browser/sync_file_system/local/canned_syncable_file_system.h
@@ -36,10 +36,6 @@
 class FileSystemURL;
 }
 
-namespace net {
-class URLRequestContext;
-}
-
 namespace storage {
 class QuotaManager;
 }
@@ -137,8 +133,7 @@
                                   FileEntryList* entries);
 
   // Returns the # of bytes written (>=0) or an error code (<0).
-  int64_t Write(net::URLRequestContext* url_request_context,
-                const storage::FileSystemURL& url,
+  int64_t Write(const storage::FileSystemURL& url,
                 std::unique_ptr<storage::BlobDataHandle> blob_data_handle);
   int64_t WriteString(const storage::FileSystemURL& url,
                       const std::string& data);
@@ -200,8 +195,7 @@
   void DoReadDirectory(const storage::FileSystemURL& url,
                        FileEntryList* entries,
                        const StatusCallback& callback);
-  void DoWrite(net::URLRequestContext* url_request_context,
-               const storage::FileSystemURL& url,
+  void DoWrite(const storage::FileSystemURL& url,
                std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
                const WriteCallback& callback);
   void DoWriteString(const storage::FileSystemURL& url,
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
index 411cdf75..d90f119 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
@@ -297,8 +297,7 @@
   EXPECT_EQ(base::File::FILE_OK,
             file_system_.CreateFile(URL(kPath4)));    // Creates another file.
   EXPECT_EQ(static_cast<int64_t>(kData.size()),       // Modifies the file.
-            file_system_.Write(&url_request_context, URL(kPath4),
-                               blob.GetBlobDataHandle()));
+            file_system_.Write(URL(kPath4), blob.GetBlobDataHandle()));
 
   // Verify the changes.
   file_system_.GetChangedURLsInTracker(&urls);
@@ -448,8 +447,8 @@
   EXPECT_EQ(base::File::FILE_OK,
             file_system_.CreateFile(URL(kPath4)));    // Creates another file.
   EXPECT_EQ(static_cast<int64_t>(kData.size()),
-            file_system_.Write(&url_request_context,  // Modifies the file.
-                               URL(kPath4), blob.GetBlobDataHandle()));
+            file_system_.Write(URL(kPath4),  // Modifies the file.
+                               blob.GetBlobDataHandle()));
 
   // Verify we have 5 changes for preparation.
   file_system_.GetChangedURLsInTracker(&urls);
diff --git a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
index 65a4edd..56658e32 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
@@ -316,7 +316,6 @@
 
   ResetCallbackStatus();
   file_system_.operation_runner()->Write(
-      &url_request_context_,
       URL(kFile), blob.GetBlobDataHandle(), 0, GetWriteCallback(FROM_HERE));
   content::RunAllTasksUntilIdle();
   EXPECT_EQ(0, callback_count_);
diff --git a/chrome/browser/sync_file_system/local/syncable_file_system_operation.cc b/chrome/browser/sync_file_system/local/syncable_file_system_operation.cc
index 09e84bc..e61a8b37 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_system_operation.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_system_operation.cc
@@ -215,7 +215,7 @@
 void SyncableFileSystemOperation::Write(
     const FileSystemURL& url,
     std::unique_ptr<storage::FileWriterDelegate> writer_delegate,
-    std::unique_ptr<net::URLRequest> blob_request,
+    std::unique_ptr<storage::BlobReader> blob_reader,
     const WriteCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (!operation_runner_.get()) {
@@ -229,7 +229,7 @@
       weak_factory_.GetWeakPtr(),
       base::Bind(
           &FileSystemOperation::Write, base::Unretained(impl_.get()), url,
-          base::Passed(&writer_delegate), base::Passed(&blob_request),
+          base::Passed(&writer_delegate), base::Passed(&blob_reader),
           base::Bind(&self::DidWrite, weak_factory_.GetWeakPtr(), callback))));
   operation_runner_->PostOperationTask(std::move(task));
 }
diff --git a/chrome/browser/sync_file_system/local/syncable_file_system_operation.h b/chrome/browser/sync_file_system/local/syncable_file_system_operation.h
index 6d662d00..9341b2894 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_system_operation.h
+++ b/chrome/browser/sync_file_system/local/syncable_file_system_operation.h
@@ -63,7 +63,7 @@
               const StatusCallback& callback) override;
   void Write(const storage::FileSystemURL& url,
              std::unique_ptr<storage::FileWriterDelegate> writer_delegate,
-             std::unique_ptr<net::URLRequest> blob_request,
+             std::unique_ptr<storage::BlobReader> blob_reader,
              const WriteCallback& callback) override;
   void Truncate(const storage::FileSystemURL& url,
                 int64_t length,
diff --git a/chrome/browser/translate/translate_service.cc b/chrome/browser/translate/translate_service.cc
index 364be494c4..aa44331 100644
--- a/chrome/browser/translate/translate_service.cc
+++ b/chrome/browser/translate/translate_service.cc
@@ -20,7 +20,6 @@
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "content/public/common/url_constants.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
@@ -105,12 +104,8 @@
 
 // static
 bool TranslateService::IsTranslateBubbleEnabled() {
-#if defined(USE_AURA)
+#if defined(USE_AURA) || defined(OS_MACOSX)
   return true;
-#elif defined(OS_MACOSX)
-  // On Mac, the translate bubble is shown instead of the infobar if the
-  // --secondary-ui-md flag is enabled.
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
 #else
   // The bubble UX is not implemented on other platforms.
   return false;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index ae06d05..fa0ae0a 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -85,10 +85,11 @@
 constexpr char kAndroidClockAppId[] = "ddmmnabaeomoacfpfjgghfpocfolhjlg";
 constexpr char kAndroidFilesAppId[] = "gmiohhmfhgfclpeacmdfancbipocempm";
 constexpr char kAndroidCameraAppId[] = "goamfaniemdfcajgcmmflhchgkmbngka";
+constexpr char kAndroidLegacyCameraAppId[] = "obfofkigjfamlldmipdegnjlcpincibc";
 
 constexpr char const* kAppIdsHiddenInLauncher[] = {
-    kAndroidClockAppId, kSettingsAppId, kAndroidFilesAppId,
-    kAndroidCameraAppId};
+    kAndroidClockAppId, kSettingsAppId, kAndroidFilesAppId, kAndroidCameraAppId,
+    kAndroidLegacyCameraAppId};
 
 // Returns true if |event_flags| came from a mouse or touch event.
 bool IsMouseOrTouchEventFromFlags(int event_flags) {
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
index 24493cf..0317cea4 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
@@ -46,6 +46,7 @@
 namespace {
 constexpr char kChromeCameraAppId[] = "hfhhnacclhffhdffklopdkcgdhifgngh";
 constexpr char kAndroidCameraAppId[] = "goamfaniemdfcajgcmmflhchgkmbngka";
+constexpr char kAndroidLegacyCameraAppId[] = "obfofkigjfamlldmipdegnjlcpincibc";
 }  // namespace
 
 const std::vector<InternalApp>& GetInternalAppList() {
@@ -121,9 +122,13 @@
   AppListClientImpl* controller = AppListClientImpl::GetInstance();
   if (arc_enabled && (!extension || media_consolidated)) {
     // Open ARC++ camera app.
-    arc::LaunchApp(profile, kAndroidCameraAppId, event_flags,
-                   arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
-                   controller->GetAppListDisplayId());
+    if (!arc::LaunchApp(profile, kAndroidCameraAppId, event_flags,
+                        arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
+                        controller->GetAppListDisplayId())) {
+      arc::LaunchApp(profile, kAndroidLegacyCameraAppId, event_flags,
+                     arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
+                     controller->GetAppListDisplayId());
+    }
   } else if (extension) {
     // Open Chrome camera app.
     AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
index 0df8b77..b981592 100644
--- a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
+++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
@@ -18,7 +18,6 @@
 #include "ui/accessibility/ax_tree_serializer.h"
 #include "ui/accessibility/ax_tree_update.h"
 #include "ui/aura/window.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/accessibility/ax_aura_obj_cache.h"
 #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
 #include "ui/views/controls/textfield/textfield.h"
@@ -102,8 +101,7 @@
   std::vector<AXAuraObjWrapper*> textfield_children;
   ax_tree.GetChildren(textfield, &textfield_children);
   // The textfield has an extra child in Harmony, the focus ring.
-  const size_t expected_children =
-      ui::MaterialDesignController::IsSecondaryUiMaterial() ? 2 : 1;
+  const size_t expected_children = 2;
   ASSERT_EQ(expected_children, textfield_children.size());
 
   ASSERT_EQ(content, textfield->GetParent());
diff --git a/chrome/browser/ui/ash/assistant/assistant_setup.cc b/chrome/browser/ui/ash/assistant/assistant_setup.cc
index a27a214..99003d8 100644
--- a/chrome/browser/ui/ash/assistant/assistant_setup.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_setup.cc
@@ -29,7 +29,6 @@
 constexpr char kAssistantSubPage[] = "googleAssistant";
 constexpr char kHotwordNotificationId[] = "assistant/hotword";
 constexpr char kNotifierAssistant[] = "assistant";
-constexpr int kAssistantIconSize = 24;
 
 // Delegate for assistant hotword notification.
 class AssistantHotwordNotificationDelegate
@@ -119,17 +118,15 @@
   const base::string16 display_source =
       base::UTF8ToUTF16(kAssistantDisplaySource);
 
-  message_center::Notification notification(
+  auto notification = message_center::Notification::CreateSystemNotification(
       message_center::NOTIFICATION_TYPE_SIMPLE, kHotwordNotificationId, title,
-      base::string16(), gfx::Image(), display_source, GURL(),
+      base::string16(), display_source, GURL(),
       message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
                                  kNotifierAssistant),
-      {}, base::MakeRefCounted<AssistantHotwordNotificationDelegate>(profile));
-
-  gfx::Image image(CreateVectorIcon(ash::kNotificationAssistantIcon,
-                                    kAssistantIconSize, gfx::kGoogleBlue700));
-  notification.set_small_image(image);
+      {}, base::MakeRefCounted<AssistantHotwordNotificationDelegate>(profile),
+      ash::kNotificationAssistantIcon,
+      message_center::SystemNotificationWarningLevel::NORMAL);
 
   NotificationDisplayService::GetForProfile(profile)->Display(
-      NotificationHandler::Type::TRANSIENT, notification);
+      NotificationHandler::Type::TRANSIENT, *notification);
 }
diff --git a/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc b/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
index a42d3c3..c338583 100644
--- a/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
+++ b/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
@@ -20,9 +20,9 @@
 namespace {
 
 // The total number of Ash accelerators.
-constexpr int kAshAcceleratorsTotalNum = 100;
+constexpr int kAshAcceleratorsTotalNum = 101;
 // The hash of Ash accelerators.
-constexpr char kAshAcceleratorsHash[] = "4232f3c0c55cc5e487c820b1c2813dcc";
+constexpr char kAshAcceleratorsHash[] = "48e2af8115132ccec79dc16ebe7da7fb";
 #if defined(GOOGLE_CHROME_BUILD)
 // Internal builds add an extra accelerator for the Feedback app.
 // The total number of Chrome accelerators (available on Chrome OS).
diff --git a/chrome/browser/ui/browser_tab_strip_tracker.cc b/chrome/browser/ui/browser_tab_strip_tracker.cc
index bfe522d..cfd10f82 100644
--- a/chrome/browser/ui/browser_tab_strip_tracker.cc
+++ b/chrome/browser/ui/browser_tab_strip_tracker.cc
@@ -68,11 +68,22 @@
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   tab_strip_model->AddObserver(tab_strip_model_observer_);
   const int active_index = tab_strip_model->active_index();
+
+  std::vector<TabStripModelChange::Delta> deltas;
   for (int i = 0; i < tab_strip_model->count(); ++i) {
+    // TODO(sangwoo108): Delete this. https://crbug.com/842194.
     tab_strip_model_observer_->TabInsertedAt(
         tab_strip_model, tab_strip_model->GetWebContentsAt(i), i,
         i == active_index);
+
+    deltas.push_back(TabStripModelChange::CreateInsertDelta(
+        tab_strip_model->GetWebContentsAt(i), i));
   }
+
+  TabStripModelChange change(TabStripModelChange::kInserted, deltas);
+  TabStripSelectionChange selection(tab_strip_model->GetActiveWebContents(),
+                                    tab_strip_model->selection_model());
+  tab_strip_model_observer_->OnTabStripModelChanged(change, selection);
 }
 
 void BrowserTabStripTracker::OnBrowserAdded(Browser* browser) {
diff --git a/chrome/browser/ui/cocoa/accelerator_utils_cocoa.mm b/chrome/browser/ui/cocoa/accelerator_utils_cocoa.mm
index d51af844..1f171bbb 100644
--- a/chrome/browser/ui/cocoa/accelerator_utils_cocoa.mm
+++ b/chrome/browser/ui/cocoa/accelerator_utils_cocoa.mm
@@ -16,6 +16,11 @@
 namespace chrome {
 
 bool IsChromeAccelerator(const ui::Accelerator& accelerator, Profile* profile) {
+  NSUInteger modifiers = (accelerator.IsCtrlDown() ? NSControlKeyMask : 0) |
+                         (accelerator.IsCmdDown() ? NSCommandKeyMask : 0) |
+                         (accelerator.IsAltDown() ? NSAlternateKeyMask : 0) |
+                         (accelerator.IsShiftDown() ? NSShiftKeyMask : 0);
+
   // The |accelerator| passed in contains a Windows key code but no platform
   // accelerator info. The Accelerator list is the opposite: It has accelerators
   // that have key_code() == VKEY_UNKNOWN but they contain a platform
@@ -23,17 +28,15 @@
   // code to a character and use that when comparing against the Accelerator
   // list.
   unichar shifted_character;
-  ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), 0, &shifted_character,
-                                  nullptr);
-  NSString* characters =
-      [[[NSString alloc] initWithCharacters:&shifted_character
-                                     length:1] autorelease];
+  unichar character;
+  int mac_keycode = ui::MacKeyCodeForWindowsKeyCode(
+      accelerator.key_code(), modifiers, &shifted_character, &character);
+  if (mac_keycode == -1)
+    return false;
 
-  NSUInteger modifiers =
-      (accelerator.IsCtrlDown() ? NSControlKeyMask : 0) |
-      (accelerator.IsCmdDown() ? NSCommandKeyMask : 0) |
-      (accelerator.IsAltDown() ? NSAlternateKeyMask : 0) |
-      (accelerator.IsShiftDown() ? NSShiftKeyMask : 0);
+  NSString* characters = [NSString stringWithFormat:@"%C", character];
+  NSString* charactersIgnoringModifiers =
+      [NSString stringWithFormat:@"%C", shifted_character];
 
   NSEvent* event = [NSEvent keyEventWithType:NSKeyDown
                                     location:NSZeroPoint
@@ -42,9 +45,9 @@
                                 windowNumber:0
                                      context:nil
                                   characters:characters
-                 charactersIgnoringModifiers:characters
+                 charactersIgnoringModifiers:charactersIgnoringModifiers
                                    isARepeat:NO
-                                     keyCode:accelerator.key_code()];
+                                     keyCode:mac_keycode];
 
   return CommandForKeyEvent(event).found();
 }
diff --git a/chrome/browser/ui/cocoa/browser_dialogs_views_mac.cc b/chrome/browser/ui/cocoa/browser_dialogs_views_mac.cc
index 57dec6f3..7184bde 100644
--- a/chrome/browser/ui/cocoa/browser_dialogs_views_mac.cc
+++ b/chrome/browser/ui/cocoa/browser_dialogs_views_mac.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/views/update_recommended_message_box.h"
 #include "chrome/common/chrome_features.h"
 #include "components/constrained_window/constrained_window_views.h"
-#include "ui/base/material_design/material_design_controller.h"
 
 // This file provides definitions of desktop browser dialog-creation methods for
 // Mac where a Cocoa browser is using Views dialogs. I.e. it is included in the
@@ -36,14 +35,9 @@
 
 namespace chrome {
 
-bool ShowPilotDialogsWithViewsToolkit() {
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
-
 bool ShowAllDialogsWithViewsToolkit() {
-  return ShowPilotDialogsWithViewsToolkit() &&
-         base::FeatureList::IsEnabled(
-             features::kShowAllDialogsWithViewsToolkit);
+  return base::FeatureList::IsEnabled(
+      features::kShowAllDialogsWithViewsToolkit);
 }
 
 void ShowPageInfoBubbleViews(Browser* browser,
diff --git a/chrome/browser/ui/cocoa/browser_dialogs_views_mac.h b/chrome/browser/ui/cocoa/browser_dialogs_views_mac.h
index 27cbde7b..2ca3b94 100644
--- a/chrome/browser/ui/cocoa/browser_dialogs_views_mac.h
+++ b/chrome/browser/ui/cocoa/browser_dialogs_views_mac.h
@@ -34,9 +34,6 @@
 
 namespace chrome {
 
-// Whether to use toolkit-views rather than Cocoa for dialogs ready to "pilot".
-bool ShowPilotDialogsWithViewsToolkit();
-
 // Whether to show all dialogs with toolkit-views on Mac, rather than Cocoa.
 bool ShowAllDialogsWithViewsToolkit();
 
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 1cf88f3..c1f2ec89 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -489,11 +489,7 @@
 }
 
 void BrowserWindowCocoa::ShowUpdateChromeDialog() {
-  if (chrome::ShowPilotDialogsWithViewsToolkit()) {
-    chrome::ShowUpdateChromeDialogViews(GetNativeWindow());
-  } else {
-    restart_browser::RequestRestart(window());
-  }
+  chrome::ShowUpdateChromeDialogViews(GetNativeWindow());
 }
 
 void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
index 9750b4f47..3e3e323 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
@@ -27,7 +27,6 @@
 #include "extensions/browser/notification_types.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/base/cocoa/window_size_constants.h"
-#include "ui/base/material_design/material_design_controller.h"
 
 using content::BrowserContext;
 using content::RenderViewHost;
@@ -181,14 +180,8 @@
                          anchoredAt:anchoredAt])) {
     beingInspected_ = devMode;
     ignoreWindowDidResignKey_ = NO;
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-      // Under MD, bubbles never have arrows.
-      [[self bubble] setArrowLocation:info_bubble::kNoArrow];
-      [[self bubble] setAlignment:info_bubble::kAlignTrailingEdgeToAnchorEdge];
-    } else {
-      [[self bubble] setArrowLocation:info_bubble::kTopTrailing];
-      [[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
-    }
+    [[self bubble] setArrowLocation:info_bubble::kNoArrow];
+    [[self bubble] setAlignment:info_bubble::kAlignTrailingEdgeToAnchorEdge];
     if (!gAnimationsEnabled)
       [window setAllowedAnimations:info_bubble::kAnimateNone];
   }
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index bfc41d9..b472721 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -292,16 +292,6 @@
 }
 
 - (NSPoint)bubblePointForDecoration:(LocationBarDecoration*)decoration {
-  // Use MD-style anchoring, even if only pilot dialogs are enabled. MD dialogs
-  // have no arrow and align corners. Cocoa dialogs will always have an arrow.
-  // This causes the arrows on Cocoa dialogs to align to the omnibox corner.
-  if (!chrome::ShowPilotDialogsWithViewsToolkit()) {
-    const NSRect frame =
-        [[self cell] frameForDecoration:decoration inFrame:[self bounds]];
-    NSPoint point = decoration->GetBubblePointInFrame(frame);
-    return [self convertPoint:point toView:nil];
-  }
-
   // Under MD, dialogs have no arrow and anchor to corner of the location bar
   // frame, not a specific point within it. See http://crbug.com/566115.
 
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
index fa85ad6..81b2603 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
@@ -26,7 +26,7 @@
 
 // Whether the toolkit-views zoom bubble should be used.
 bool UseViews() {
-  return chrome::ShowPilotDialogsWithViewsToolkit();
+  return true;
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/login_handler_cocoa.mm b/chrome/browser/ui/cocoa/login_handler_cocoa.mm
index 1a436ba8c..b947f7a 100644
--- a/chrome/browser/ui/cocoa/login_handler_cocoa.mm
+++ b/chrome/browser/ui/cocoa/login_handler_cocoa.mm
@@ -141,12 +141,8 @@
     net::AuthChallengeInfo* auth_info,
     content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
     LoginAuthRequiredCallback auth_required_callback) {
-  if (chrome::ShowPilotDialogsWithViewsToolkit()) {
-    return chrome::CreateLoginHandlerViews(auth_info, web_contents_getter,
-                                           std::move(auth_required_callback));
-  }
-  return base::MakeRefCounted<LoginHandlerMac>(
-      auth_info, web_contents_getter, std::move(auth_required_callback));
+  return chrome::CreateLoginHandlerViews(auth_info, web_contents_getter,
+                                         std::move(auth_required_callback));
 }
 
 // ----------------------------------------------------------------------------
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
index 9cd13b7..488ff778 100644
--- a/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/mac/scoped_cftyperef.h"
+#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
 
 namespace {
 bool g_is_input_source_dvorak_qwerty = false;
@@ -127,24 +128,15 @@
   // We typically want to compare [NSMenuItem keyEquivalent] against [NSEvent
   // charactersIgnoringModifiers]. There is a special keyboard layout "Dvorak -
   // QWERTY" which uses QWERTY-style shortcuts when the Command key is held
-  // down. In this case, we want to use [NSEvent characters] instead of [NSEvent
-  // charactersIgnoringModifiers]. The problem is, this has the wrong behavior
-  // for every other keyboard layout.
-  //
-  // The documentation for -[NSEvent charactersIgnoringModifiers] states that
-  // it is the appropriate method to use for implementing keyEquivalents.
+  // down. In this case, we want to use the keycode of the event rather than
+  // looking at the characters.
   if (g_is_input_source_dvorak_qwerty) {
-    // When both |characters| and |charactersIgnoringModifiers| are ascii, we
-    // want to use |characters| if it's a character and
-    // |charactersIgnoringModifiers| else (on dvorak, cmd-shift-z should fire
-    // "cmd-:" instead of "cmd-;", but on dvorak-qwerty, cmd-shift-z should fire
-    // cmd-shift-z instead of cmd-:).
-    if ([eventString characterAtIndex:0] <= 0x7f &&
-        [[event characters] length] > 0 &&
-        [[event characters] characterAtIndex:0] <= 0x7f &&
-        isalpha([[event characters] characterAtIndex:0])) {
-      eventString = [event characters];
-    }
+    ui::KeyboardCode windows_keycode =
+        ui::KeyboardCodeFromKeyCode(event.keyCode);
+    unichar shifted_character, character;
+    ui::MacKeyCodeForWindowsKeyCode(windows_keycode, event.modifierFlags,
+                                    &shifted_character, &character);
+    eventString = [NSString stringWithFormat:@"%C", shifted_character];
   }
 
   // [ctr + shift + tab] generates the "End of Medium" keyEquivalent rather than
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
index 41823864..9884e1d 100644
--- a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
@@ -267,12 +267,30 @@
   ExpectKeyDoesntFireItem(key, MenuItem(@"z", 0x100000));
   ExpectKeyFiresItem(key, MenuItem(@";", 0x100000));
 
+  // Change to Dvorak-QWERTY
+  SetIsInputSourceDvorakQwertyForTesting(true);
+
   // cmd-z on dvorak qwerty layout (so that the key produces ';', but 'z' if
   // cmd is down)
-  SetIsInputSourceDvorakQwertyForTesting(true);
   key = KeyEvent(0x100108, @"z", @";", 6);
   ExpectKeyFiresItem(key, MenuItem(@"z", 0x100000), false);
   ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000), false);
+
+  // On dvorak-qwerty, pressing the keys for 'cmd' and '=' triggers an event
+  // whose characters are cmd-'+'.
+  // cmd-'+' on dvorak qwerty should not trigger a menu item for cmd-']', and
+  // not a menu item for cmd-'+'.
+  key = KeyEvent(0x100108, @"+", @"+", 30);
+  ExpectKeyFiresItem(key, MenuItem(@"]", 0x100000), false);
+  ExpectKeyDoesntFireItem(key, MenuItem(@"+", 0x100000), false);
+
+  // cmd-shift-'+' on dvorak qwerty should trigger a menu item for cmd-shift-'}'
+  // and not a menu item for cmd-shift-'+'.
+  key = KeyEvent(0x12010a, @"}", @"+", 30);
+  ExpectKeyFiresItem(key, MenuItem(@"}", 0x100000), false);
+  ExpectKeyDoesntFireItem(key, MenuItem(@"+", 0x100000), false);
+
+  // Change away from Dvorak-QWERTY
   SetIsInputSourceDvorakQwertyForTesting(false);
 
   // cmd-shift-z on dvorak layout (so that we get a ':')
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
index 5b2b8c6b..d6a311f 100644
--- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
@@ -44,7 +44,8 @@
   if ((self = [super init])) {
     controller_ = controller;
 
-    if (base::FeatureList::IsEnabled(features::kTextSuggestionsTouchBar)) {
+    if (base::FeatureList::IsEnabled(features::kTextSuggestionsTouchBar) ||
+        base::FeatureList::IsEnabled(features::kExperimentalUi)) {
       textSuggestionsTouchBarController_.reset(
           [[TextSuggestionsTouchBarController alloc]
               initWithWebContents:[controller_ webContents]
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index a4d98a20..0c69708 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -64,7 +64,6 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/resources/grit/ui_resources.h"
@@ -1013,18 +1012,11 @@
   else
     title = base::UTF8ToUTF16(url.spec());
 
-  const bool use_md = ui::MaterialDesignController::IsSecondaryUiMaterial();
-  if (use_md) {
-    // Format the title to include the unicode single dot bullet code-point
-    // \u2022 and two spaces.
-    title = l10n_util::GetStringFUTF16(IDS_LIST_BULLET, title);
-  }
+  // Format the title to include the unicode single dot bullet code-point \u2022
+  // and two spaces.
+  title = l10n_util::GetStringFUTF16(IDS_LIST_BULLET, title);
 
-  return ListItem(use_md
-                      ? gfx::Image()
-                      : ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-                            IDR_DEFAULT_FAVICON),
-                  title, true, id);
+  return ListItem(gfx::Image(), title, true, id);
 }
 
 void ContentSettingPopupBubbleModel::OnListItemClicked(int index,
@@ -1646,18 +1638,11 @@
                              ? base::UTF8ToUTF16(url.spec())
                              : l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE);
 
-  const bool use_md = ui::MaterialDesignController::IsSecondaryUiMaterial();
-  if (use_md) {
-    // Format the title to include the unicode single dot bullet code-point
-    // \u2022 and two spaces.
-    title = l10n_util::GetStringFUTF16(IDS_LIST_BULLET, title);
-  }
+  // Format the title to include the unicode single dot bullet code-point
+  // \u2022 and two spaces.
+  title = l10n_util::GetStringFUTF16(IDS_LIST_BULLET, title);
 
-  gfx::Image image =
-      use_md ? gfx::Image()
-             : ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-                   IDR_DEFAULT_FAVICON);
-  return ListItem(image, title, true, 0);
+  return ListItem(gfx::Image(), title, true, 0);
 }
 
 // ContentSettingBubbleModel ---------------------------------------------------
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc
index e968f1b7..a33b8008 100644
--- a/chrome/browser/ui/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.cc
@@ -54,9 +54,7 @@
       // move to views/layout_provider.h so that all bubbles are consistent.
       return newer_material ? 8 : 2;
     case LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET:
-      if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-        return 1;
-      return hybrid ? 8 : 6;
+      return 1;
     case LOCATION_BAR_ELEMENT_PADDING: {
       const int kPadding[] = {1, 3, 3, 2, 3};
       return kPadding[mode];
diff --git a/chrome/browser/ui/page_info/permission_menu_model.cc b/chrome/browser/ui/page_info/permission_menu_model.cc
index 8e943a32..add1cfe39 100644
--- a/chrome/browser/ui/page_info/permission_menu_model.cc
+++ b/chrome/browser/ui/page_info/permission_menu_model.cc
@@ -12,7 +12,6 @@
 #include "content/public/common/origin_util.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 
 PermissionMenuModel::PermissionMenuModel(Profile* profile,
                                          const GURL& url,
@@ -28,6 +27,7 @@
 
   // Retrieve the string to show for the default setting for this permission.
   ContentSetting effective_default_setting = permission_.default_setting;
+  DCHECK_NE(effective_default_setting, CONTENT_SETTING_NUM_SETTINGS);
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   effective_default_setting = PluginsFieldTrial::EffectiveContentSetting(
@@ -35,51 +35,20 @@
       permission_.default_setting);
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 
-  switch (effective_default_setting) {
-    case CONTENT_SETTING_ALLOW:
-      label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_DEFAULT_ALLOW);
-      break;
-    case CONTENT_SETTING_BLOCK:
-      label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_DEFAULT_BLOCK);
-      break;
-    case CONTENT_SETTING_ASK:
-      label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_DEFAULT_ASK);
-      break;
-    case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT:
-      // TODO(tommycli): We display the ASK string for DETECT because with
-      // HTML5 by Default, Chrome will ask before running Flash on most sites.
-      // Once the feature flag is gone, migrate the actual setting to ASK.
-      label = l10n_util::GetStringUTF16(
-          PluginUtils::ShouldPreferHtmlOverPlugins(host_content_settings_map_)
-              ? IDS_PAGE_INFO_MENU_ITEM_DEFAULT_ASK
-              : IDS_PAGE_INFO_MENU_ITEM_DEFAULT_DETECT_IMPORTANT_CONTENT);
-      break;
-    case CONTENT_SETTING_NUM_SETTINGS:
-      NOTREACHED();
-      break;
-    default:
-      break;
-  }
-
   // The Material UI for site settings uses comboboxes instead of menubuttons,
   // which means the elements of the menu themselves have to be shorter, instead
   // of simply setting a shorter label on the menubutton.
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    label = PageInfoUI::PermissionActionToUIString(
-        profile, permission_.type, CONTENT_SETTING_DEFAULT,
-        effective_default_setting, permission_.source);
-  }
+  label = PageInfoUI::PermissionActionToUIString(
+      profile, permission_.type, CONTENT_SETTING_DEFAULT,
+      effective_default_setting, permission_.source);
 
   AddCheckItem(CONTENT_SETTING_DEFAULT, label);
 
   // Retrieve the string to show for allowing the permission.
   if (ShouldShowAllow(url)) {
-    label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_ALLOW);
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-      label = PageInfoUI::PermissionActionToUIString(
-          profile, permission_.type, CONTENT_SETTING_ALLOW,
-          effective_default_setting, permission_.source);
-    }
+    label = PageInfoUI::PermissionActionToUIString(
+        profile, permission_.type, CONTENT_SETTING_ALLOW,
+        effective_default_setting, permission_.source);
     AddCheckItem(CONTENT_SETTING_ALLOW, label);
   }
 
@@ -94,26 +63,17 @@
   }
 
   // Retrieve the string to show for blocking the permission.
-  label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_BLOCK);
-  if (permission_.type == CONTENT_SETTINGS_TYPE_ADS) {
-    label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_ADS_BLOCK);
-  }
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    label = PageInfoUI::PermissionActionToUIString(
-        profile, info.type, CONTENT_SETTING_BLOCK, effective_default_setting,
-        info.source);
-  }
+  label = PageInfoUI::PermissionActionToUIString(
+      profile, info.type, CONTENT_SETTING_BLOCK, effective_default_setting,
+      info.source);
   AddCheckItem(CONTENT_SETTING_BLOCK, label);
 
   // Retrieve the string to show for allowing the user to be asked about the
   // permission.
   if (ShouldShowAsk(url)) {
-    label = l10n_util::GetStringUTF16(IDS_PAGE_INFO_MENU_ITEM_ASK);
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-      label = PageInfoUI::PermissionActionToUIString(
-          profile, info.type, CONTENT_SETTING_ASK, effective_default_setting,
-          info.source);
-    }
+    label = PageInfoUI::PermissionActionToUIString(
+        profile, info.type, CONTENT_SETTING_ASK, effective_default_setting,
+        info.source);
     AddCheckItem(CONTENT_SETTING_ASK, label);
   }
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index d5d831b1..00caf563 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -62,21 +62,6 @@
                                       ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
 }
 
-// Fill TabStripSelectionChange with given |contents| and |selection_model|.
-// note that |new_contents| and |new_model| will be filled too so that
-// selection_changed() and active_tab_changed() won't return true.
-TabStripSelectionChange GetDefaultSelection(
-    content::WebContents* contents,
-    const ui::ListSelectionModel& selection_model) {
-  TabStripSelectionChange selection;
-  selection.old_contents = contents;
-  selection.new_contents = contents;
-  selection.old_model = selection_model;
-  selection.new_model = selection_model;
-  selection.reason = 0;
-  return selection;
-}
-
 // This tracks (and reports via UMA and tracing) how long it takes before a
 // RenderWidgetHost is requested to become visible.
 class RenderWidgetHostVisibilityTracker
@@ -358,8 +343,7 @@
   if (manager)
     data->set_blocked(manager->IsDialogActive());
 
-  TabStripSelectionChange selection =
-      GetDefaultSelection(GetActiveWebContents(), selection_model_);
+  TabStripSelectionChange selection(GetActiveWebContents(), selection_model_);
 
   contents_data_.insert(contents_data_.begin() + index, std::move(data));
 
@@ -376,9 +360,9 @@
                              /*triggered_by_other_operation=*/true);
   }
 
-  base::Optional<TabStripModelChange> change(TabStripModelChange(
+  TabStripModelChange change(
       TabStripModelChange::kInserted,
-      TabStripModelChange::CreateInsertDelta(raw_contents, index)));
+      TabStripModelChange::CreateInsertDelta(raw_contents, index));
   for (auto& observer : observers_)
     observer.OnTabStripModelChanged(change, selection);
 }
@@ -392,8 +376,7 @@
 
   FixOpenersAndGroupsReferencing(index);
 
-  TabStripSelectionChange selection =
-      GetDefaultSelection(GetActiveWebContents(), selection_model_);
+  TabStripSelectionChange selection(GetActiveWebContents(), selection_model_);
   WebContents* raw_new_contents = new_contents.get();
   std::unique_ptr<WebContents> old_contents =
       contents_data_[index]->ReplaceWebContents(std::move(new_contents));
@@ -414,10 +397,9 @@
     }
   }
 
-  base::Optional<TabStripModelChange> change(
-      TabStripModelChange(TabStripModelChange::kReplaced,
-                          TabStripModelChange::CreateReplaceDelta(
-                              old_contents.get(), raw_new_contents, index)));
+  TabStripModelChange change(TabStripModelChange::kReplaced,
+                             TabStripModelChange::CreateReplaceDelta(
+                                 old_contents.get(), raw_new_contents, index));
   for (auto& observer : observers_)
     observer.OnTabStripModelChanged(change, selection);
 
@@ -573,8 +555,7 @@
       observer.TabStripEmpty();
   }
 
-  base::Optional<TabStripModelChange> change(
-      TabStripModelChange(TabStripModelChange::kRemoved, deltas));
+  TabStripModelChange change(TabStripModelChange::kRemoved, deltas);
   for (auto& observer : observers_)
     observer.OnTabStripModelChanged(change, selection);
 }
@@ -1553,8 +1534,9 @@
 
   if (!triggered_by_other_operation &&
       (selection.active_tab_changed() || selection.selection_changed())) {
+    TabStripModelChange change;
     for (auto& observer : observers_)
-      observer.OnTabStripModelChanged({}, selection);
+      observer.OnTabStripModelChanged(change, selection);
   }
 
   return selection;
@@ -1577,8 +1559,7 @@
                                           bool select_after_move) {
   FixOpenersAndGroupsReferencing(index);
 
-  TabStripSelectionChange selection =
-      GetDefaultSelection(GetActiveWebContents(), selection_model_);
+  TabStripSelectionChange selection(GetActiveWebContents(), selection_model_);
 
   std::unique_ptr<WebContentsData> moved_data =
       std::move(contents_data_[index]);
@@ -1597,9 +1578,9 @@
   for (auto& observer : observers_)
     observer.TabMoved(web_contents, index, to_position);
 
-  base::Optional<TabStripModelChange> change(TabStripModelChange(
+  TabStripModelChange change(
       TabStripModelChange::kMoved,
-      TabStripModelChange::CreateMoveDelta(web_contents, index, to_position)));
+      TabStripModelChange::CreateMoveDelta(web_contents, index, to_position));
   for (auto& observer : observers_)
     observer.OnTabStripModelChanged(change, selection);
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.cc b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
index f358b01..9e45343 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
@@ -45,6 +45,8 @@
   return delta;
 }
 
+TabStripModelChange::TabStripModelChange() = default;
+
 TabStripModelChange::TabStripModelChange(Type type, const Delta& delta)
     : type_(type), deltas_({delta}) {}
 
@@ -59,11 +61,20 @@
 
 TabStripSelectionChange::TabStripSelectionChange() = default;
 
+TabStripSelectionChange::TabStripSelectionChange(
+    content::WebContents* contents,
+    const ui::ListSelectionModel& selection_model)
+    : old_contents(contents),
+      new_contents(contents),
+      old_model(selection_model),
+      new_model(selection_model),
+      reason(0) {}
+
 TabStripModelObserver::TabStripModelObserver() {
 }
 
 void TabStripModelObserver::OnTabStripModelChanged(
-    const base::Optional<TabStripModelChange>& change,
+    const TabStripModelChange& change,
     const TabStripSelectionChange& selection) {}
 
 void TabStripModelObserver::TabInsertedAt(TabStripModel* tab_strip_model,
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.h b/chrome/browser/ui/tabs/tab_strip_model_observer.h
index 10295cae..42fa5e0e 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.h
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.h
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/optional.h"
 #include "chrome/browser/ui/tabs/tab_change_type.h"
 #include "ui/base/models/list_selection_model.h"
 
@@ -33,12 +32,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 class TabStripModelChange {
  public:
-  enum Type {
-    kInserted,
-    kRemoved,
-    kMoved,
-    kReplaced,
-  };
+  enum Type { kSelectionOnly, kInserted, kRemoved, kMoved, kReplaced };
 
   // A WebContents was inserted at |index|. This implicitly changes the existing
   // selection model by calling IncrementFrom(index).
@@ -97,6 +91,7 @@
                                   content::WebContents* new_contents,
                                   int index);
 
+  TabStripModelChange();
   TabStripModelChange(Type type, const Delta& delta);
   TabStripModelChange(Type type, const std::vector<Delta>& deltas);
   ~TabStripModelChange();
@@ -107,7 +102,7 @@
   const std::vector<Delta>& deltas() const { return deltas_; }
 
  private:
-  const Type type_;
+  const Type type_ = kSelectionOnly;
   const std::vector<Delta> deltas_;
 
   DISALLOW_COPY_AND_ASSIGN(TabStripModelChange);
@@ -117,6 +112,12 @@
 struct TabStripSelectionChange {
   TabStripSelectionChange();
 
+  // Fill TabStripSelectionChange with given |contents| and |selection_model|.
+  // note that |new_contents| and |new_model| will be filled too so that
+  // selection_changed() and active_tab_changed() won't return true.
+  TabStripSelectionChange(content::WebContents* contents,
+                          const ui::ListSelectionModel& model);
+
   bool active_tab_changed() const { return old_contents != new_contents; }
 
   // TODO(sangwoo.ko) Do we need something to indicate that the change
@@ -172,9 +173,8 @@
   // TabStripModel before the |change| and after the |change| are applied.
   // When only selection/activation was changed without any change about
   // WebContents, |change| can be empty.
-  virtual void OnTabStripModelChanged(
-      const base::Optional<TabStripModelChange>& change,
-      const TabStripSelectionChange& selection);
+  virtual void OnTabStripModelChanged(const TabStripModelChange& change,
+                                      const TabStripSelectionChange& selection);
 
   // A new WebContents was inserted into the TabStripModel at the
   // specified index. |foreground| is whether or not it was opened in the
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index f2ee0cd..f401c3c 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -377,48 +377,46 @@
 
   // TabStripModelObserver implementation:
   void OnTabStripModelChanged(
-      const base::Optional<TabStripModelChange>& change,
+      const TabStripModelChange& change,
       const TabStripSelectionChange& selection) override {
-    if (change) {
-      switch (change->type()) {
-        case TabStripModelChange::kInserted: {
-          for (const auto& delta : change->deltas()) {
-            PushInsertState(delta.insert.contents, delta.insert.index,
-                            selection.new_contents == delta.insert.contents);
-          }
-          break;
+    switch (change.type()) {
+      case TabStripModelChange::kInserted: {
+        for (const auto& delta : change.deltas()) {
+          PushInsertState(delta.insert.contents, delta.insert.index,
+                          selection.new_contents == delta.insert.contents);
         }
-        case TabStripModelChange::kRemoved: {
-          for (const auto& delta : change->deltas()) {
-            if (delta.remove.will_be_deleted)
-              PushCloseState(delta.remove.contents, delta.remove.index);
-
-            PushDetachState(delta.remove.contents, delta.remove.index,
-                            selection.old_contents == delta.remove.contents);
-          }
-          break;
-        }
-        case TabStripModelChange::kReplaced: {
-          for (const auto& delta : change->deltas()) {
-            PushReplaceState(delta.replace.old_contents,
-                             delta.replace.new_contents, delta.replace.index);
-          }
-          break;
-        }
-        case TabStripModelChange::kMoved: {
-          for (const auto& delta : change->deltas()) {
-            PushMoveState(delta.move.contents, delta.move.from_index,
-                          delta.move.to_index);
-          }
-          // Selection change triggered by move shouldn't be counted as
-          // exsiting tests don't expect selection change in this case.
-          // TODO(sangwoo.ko): Update the tests in this class to not use the
-          // deprecated callbacks. https://crbug.com/842194
-          return;
-        }
-        default:
-          NOTREACHED();
+        break;
       }
+      case TabStripModelChange::kRemoved: {
+        for (const auto& delta : change.deltas()) {
+          if (delta.remove.will_be_deleted)
+            PushCloseState(delta.remove.contents, delta.remove.index);
+
+          PushDetachState(delta.remove.contents, delta.remove.index,
+                          selection.old_contents == delta.remove.contents);
+        }
+        break;
+      }
+      case TabStripModelChange::kReplaced: {
+        for (const auto& delta : change.deltas()) {
+          PushReplaceState(delta.replace.old_contents,
+                           delta.replace.new_contents, delta.replace.index);
+        }
+        break;
+      }
+      case TabStripModelChange::kMoved: {
+        for (const auto& delta : change.deltas()) {
+          PushMoveState(delta.move.contents, delta.move.from_index,
+                        delta.move.to_index);
+        }
+        // Selection change triggered by move shouldn't be counted as
+        // exsiting tests don't expect selection change in this case.
+        // TODO(sangwoo.ko): Update the tests in this class to not use the
+        // deprecated callbacks. https://crbug.com/842194
+        return;
+      }
+      default:
+        break;
     }
 
     if (selection.active_tab_changed()) {
diff --git a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
index 3ed6da6..4206451 100644
--- a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
+++ b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/mojo/media_router_mojo_impl.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/media_router/cloud_services_dialog.h"
 #include "chrome/browser/ui/singleton_tabs.h"
@@ -27,10 +27,10 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "extensions/common/constants.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "ui/base/models/menu_model_delegate.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -136,9 +136,9 @@
   if (command_id == IDC_MEDIA_ROUTER_CLOUD_SERVICES_TOGGLE) {
     // Cloud services preference is not set or used if the user is not signed
     // in.
-    SigninManagerBase* signin_manager =
-        SigninManagerFactory::GetForProfile(browser_->profile());
-    return signin_manager && signin_manager->IsAuthenticated();
+    identity::IdentityManager* identity_manager =
+        IdentityManagerFactory::GetForProfile(browser_->profile());
+    return identity_manager && identity_manager->HasPrimaryAccount();
   }
   return true;
 }
diff --git a/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc b/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc
index cacfe65..747d23fb 100644
--- a/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc
+++ b/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/test/mock_media_router.h"
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/extensions/browser_action_test_util.h"
 #include "chrome/browser/ui/media_router/media_router_ui_service.h"
@@ -24,6 +25,8 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -74,8 +77,6 @@
         extensions::extension_action_test_util::CreateToolbarModelForProfile(
             profile());
 
-    signin_manager_ =
-        SigninManagerFactory::GetInstance()->GetForProfile(profile());
     browser_action_test_util_ = BrowserActionTestUtil::Create(browser(), false);
     action_ = std::make_unique<MediaRouterAction>(
         browser(), browser_action_test_util_->GetToolbarActionsBar());
@@ -97,13 +98,14 @@
     return {{media_router::MediaRouterFactory::GetInstance(),
              &media_router::MockMediaRouter::Create},
             {media_router::MediaRouterUIServiceFactory::GetInstance(),
-             &BuildUIService}};
+             &BuildUIService},
+            {SigninManagerFactory::GetInstance(), &BuildFakeSigninManagerBase}};
   }
 
  protected:
   std::unique_ptr<BrowserActionTestUtil> browser_action_test_util_;
   std::unique_ptr<MediaRouterAction> action_;
-  SigninManagerBase* signin_manager_ = nullptr;
+
   ToolbarActionsModel* toolbar_actions_model_ = nullptr;
   MockMediaRouterContextualMenuObserver observer_;
 
@@ -146,7 +148,9 @@
   }
 
   // Set up an authenticated account.
-  signin_manager_->SetAuthenticatedAccountInfo("foo@bar.com", "password");
+  (void)identity::SetPrimaryAccount(
+      SigninManagerFactory::GetInstance()->GetForProfile(profile()),
+      IdentityManagerFactory::GetForProfile(profile()), "foo@bar.com");
 
   // Run the same checks as before. All existing menu items should be now
   // enabled and visible.
@@ -205,7 +209,9 @@
 
   // Set up an authenticated account such that the cloud services menu item is
   // surfaced. Whether or not it is surfaced is tested in the "Basic" test.
-  signin_manager_->SetAuthenticatedAccountInfo("foo@bar.com", "password");
+  (void)identity::SetPrimaryAccount(
+      SigninManagerFactory::GetInstance()->GetForProfile(profile()),
+      IdentityManagerFactory::GetForProfile(profile()), "foo@bar.com");
 
   // Set this preference so that the cloud services can be enabled without
   // showing the opt-in dialog.
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
index 40ec0cda..a86c731 100644
--- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
@@ -22,7 +22,6 @@
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
@@ -280,8 +279,7 @@
 }
 
 bool CardUnmaskPromptViews::ShouldShowCloseButton() const {
-  // Material UI has no [X] in the corner of this dialog.
-  return !ui::MaterialDesignController::IsSecondaryUiMaterial();
+  return false;
 }
 
 bool CardUnmaskPromptViews::Cancel() {
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
index 85194a5..ef4c3a7 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
@@ -17,7 +17,6 @@
 #include "components/autofill/core/browser/ui/local_card_migration_bubble_controller.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
@@ -80,9 +79,7 @@
 }
 
 int LocalCardMigrationBubbleViews::GetDialogButtons() const {
-  return ui::MaterialDesignController::IsSecondaryUiMaterial()
-             ? ui::DIALOG_BUTTON_OK
-             : ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  return ui::DIALOG_BUTTON_OK;
 }
 
 base::string16 LocalCardMigrationBubbleViews::GetDialogButtonLabel(
@@ -116,7 +113,7 @@
 }
 
 bool LocalCardMigrationBubbleViews::ShouldShowCloseButton() const {
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
+  return true;
 }
 
 void LocalCardMigrationBubbleViews::WindowClosing() {
@@ -138,4 +135,4 @@
   AddChildView(explanatory_message);
 }
 
-}  // namespace autofill
\ No newline at end of file
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index 21e8bb34..7a54a95 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -17,7 +17,6 @@
 #include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
@@ -120,10 +119,7 @@
 }
 
 int SaveCardBubbleViews::GetDialogButtons() const {
-  // Material UI has no "No thanks" button in favor of an [X].
-  return ui::MaterialDesignController::IsSecondaryUiMaterial()
-             ? ui::DIALOG_BUTTON_OK
-             : ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  return ui::DIALOG_BUTTON_OK;
 }
 
 gfx::Size SaveCardBubbleViews::CalculatePreferredSize() const {
@@ -183,8 +179,7 @@
 }
 
 bool SaveCardBubbleViews::ShouldShowCloseButton() const {
-  // The [X] is shown for Material UI.
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
+  return true;
 }
 
 base::string16 SaveCardBubbleViews::GetWindowTitle() const {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
index ece5f03..85eb408 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -26,7 +26,6 @@
 #include "components/user_prefs/user_prefs.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/events/event.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/md_text_button.h"
@@ -43,13 +42,6 @@
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
 
-namespace {
-
-// Background color of text field when URL is invalid.
-const SkColor kErrorColor = SkColorSetRGB(0xFF, 0xBC, 0xBC);
-
-}  // namespace
-
 BookmarkEditorView::BookmarkEditorView(
     Profile* profile,
     const BookmarkNode* parent,
@@ -454,12 +446,7 @@
 void BookmarkEditorView::UserInputChanged() {
   if (details_.GetNodeType() != BookmarkNode::FOLDER) {
     const GURL url(GetInputURL());
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-      url_tf_->SetInvalid(!url.is_valid());
-    else if (!url.is_valid())
-      url_tf_->SetBackgroundColor(kErrorColor);
-    else
-      url_tf_->UseDefaultBackgroundColor();
+    url_tf_->SetInvalid(!url.is_valid());
   }
   DialogModelChanged();
 }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index e777a3c..f34eb83 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -102,6 +102,33 @@
   return !MD::IsRefreshUi();
 }
 
+bool BrowserNonClientFrameView::HasVisibleBackgroundTabShapes() const {
+  DCHECK(browser_view()->IsTabStripVisible());
+
+  // Pre-refresh, background tab shapes are always visible.
+  if (!MD::IsRefreshUi())
+    return true;
+
+  // When custom imagery is involved in drawing the tabstrip, assume tab shapes
+  // are visible if the tabs use a custom image for a background directly, or if
+  // the frame image has been tinted visibly.  If the tabs use the same image as
+  // the frame, just shifted to look as if it aligns, this will report that
+  // shapes are visible when they aren't.  To detect this, we'd need to do some
+  // sort of aligned image comparison, which seems harder than it's worth.
+  bool has_custom_image;
+  const int fill_id =
+      browser_view()->tabstrip()->GetBackgroundResourceId(&has_custom_image);
+  if (has_custom_image) {
+    return GetThemeProvider()->HasCustomImage(fill_id) ||
+           color_utils::IsHSLShiftMeaningful(GetThemeProvider()->GetTint(
+               ThemeProperties::TINT_BACKGROUND_TAB));
+  }
+
+  // Background tab shapes are visible iff the tab color differs from the frame
+  // color.
+  return GetTabBackgroundColor(TAB_INACTIVE) != GetFrameColor();
+}
+
 gfx::ImageSkia BrowserNonClientFrameView::GetIncognitoAvatarIcon() const {
   const SkColor icon_color = color_utils::PickContrastingColor(
       SK_ColorWHITE, gfx::kChromeIconGrey, GetFrameColor());
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index c58a01d..ef4aaff 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -78,6 +78,10 @@
   // Returns whether the content is painted with a client edge or not.
   virtual bool HasClientEdge() const;
 
+  // Returns whether the shapes of background tabs are visible against the
+  // frame.
+  virtual bool HasVisibleBackgroundTabShapes() const;
+
   // Retrieves the icon to use in the frame to indicate an incognito window.
   gfx::ImageSkia GetIncognitoAvatarIcon() const;
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index c6695a3..9a8c3f1 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1247,30 +1247,22 @@
   LocationBarView* location_bar = GetLocationBarView();
   PageActionIconView* card_view = location_bar->save_credit_card_icon_view();
 
-  views::View* anchor_view = location_bar;
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    if (card_view && card_view->visible())
-      anchor_view = card_view;
-    else
-      anchor_view = toolbar_button_provider()->GetAppMenuButton();
-  }
-
   autofill::BubbleType bubble_type = controller->GetBubbleType();
   autofill::SaveCardBubbleViews* bubble = nullptr;
 
   switch (bubble_type) {
     case autofill::BubbleType::LOCAL_SAVE:
     case autofill::BubbleType::UPLOAD_SAVE:
-      bubble = new autofill::SaveCardOfferBubbleViews(anchor_view, gfx::Point(),
-                                                      web_contents, controller);
+      bubble = new autofill::SaveCardOfferBubbleViews(
+          location_bar, gfx::Point(), web_contents, controller);
       break;
     case autofill::BubbleType::SIGN_IN_PROMO:
       bubble = new autofill::SaveCardSignInPromoBubbleViews(
-          anchor_view, gfx::Point(), web_contents, controller);
+          location_bar, gfx::Point(), web_contents, controller);
       break;
     case autofill::BubbleType::MANAGE_CARDS:
       bubble = new autofill::SaveCardManageCardsBubbleViews(
-          anchor_view, gfx::Point(), web_contents, controller);
+          location_bar, gfx::Point(), web_contents, controller);
       break;
     case autofill::BubbleType::INACTIVE:
       break;
@@ -1296,16 +1288,8 @@
   PageActionIconView* card_view =
       location_bar->local_card_migration_icon_view();
 
-  views::View* anchor_view = location_bar;
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    if (card_view && card_view->visible())
-      anchor_view = card_view;
-    else
-      anchor_view = toolbar_button_provider()->GetAppMenuButton();
-  }
-
   autofill::LocalCardMigrationBubbleViews* bubble =
-      new autofill::LocalCardMigrationBubbleViews(anchor_view, gfx::Point(),
+      new autofill::LocalCardMigrationBubbleViews(location_bar, gfx::Point(),
                                                   web_contents, controller);
   views::Widget* bubble_widget =
       views::BubbleDialogDelegateView::CreateBubble(bubble);
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 1ea2e43b..8be5035 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -171,6 +171,23 @@
          BrowserNonClientFrameView::HasClientEdge();
 }
 
+bool GlassBrowserFrameView::HasVisibleBackgroundTabShapes() const {
+  // Pre-Win 8, tabs never match the glass frame appearance.
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return true;
+
+  // Enabling high contrast mode disables the custom-drawn titlebar (so the
+  // system-drawn frame will respect the native frame colors) and enables the
+  // IncreasedContrastThemeSupplier (which does not respect the native frame
+  // colors).
+  // TODO(pkasting): https://crbug.com/831769  Change the architecture of the
+  // high contrast support to respect system colors, then remove this.
+  if (ui::NativeTheme::GetInstanceForNativeUi()->UsesHighContrastColors())
+    return true;
+
+  return BrowserNonClientFrameView::HasVisibleBackgroundTabShapes();
+}
+
 void GlassBrowserFrameView::UpdateThrobber(bool running) {
   if (ShowCustomIcon())
     window_icon_->Update();
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index 5ccd6eb..dc098a1 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -39,6 +39,7 @@
   int GetTopInset(bool restored) const override;
   int GetThemeBackgroundXInset() const override;
   bool HasClientEdge() const override;
+  bool HasVisibleBackgroundTabShapes() const override;
   void UpdateThrobber(bool running) override;
   gfx::Size GetMinimumSize() const override;
   int GetTabStripLeftInset() const override;
diff --git a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
index 07a5f07..e7b6c45 100644
--- a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
+++ b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
@@ -38,11 +38,12 @@
 // static
 std::unique_ptr<views::LayoutProvider>
 ChromeLayoutProvider::CreateLayoutProvider() {
+  // TODO(pbos): Consolidate HarmonyLayoutProvider into ChromeLayoutProvider as
+  // it is no longer active, or wait until Refresh is always on then consolidate
+  // all three.
   if (ui::MaterialDesignController::IsRefreshUi())
     return std::make_unique<MaterialRefreshLayoutProvider>();
-  return ui::MaterialDesignController::IsSecondaryUiMaterial()
-             ? std::make_unique<HarmonyLayoutProvider>()
-             : std::make_unique<ChromeLayoutProvider>();
+  return std::make_unique<HarmonyLayoutProvider>();
 }
 
 gfx::Insets ChromeLayoutProvider::GetInsetsMetric(int metric) const {
diff --git a/chrome/browser/ui/views/hover_button.cc b/chrome/browser/ui/views/hover_button.cc
index 73e6301e..c7ac2da 100644
--- a/chrome/browser/ui/views/hover_button.cc
+++ b/chrome/browser/ui/views/hover_button.cc
@@ -9,7 +9,6 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/harmony/chrome_typography.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop_highlight.h"
@@ -80,9 +79,6 @@
   SetBorder(CreateBorderWithVerticalSpacing(vert_spacing));
 
   SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
-  // Don't show the ripple on non-MD.
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial())
-    set_ink_drop_visible_opacity(0);
 }
 
 HoverButton::HoverButton(views::ButtonListener* button_listener,
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 1b095f8..9c611de 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/theme_provider.h"
 #include "ui/events/event_utils.h"
 #include "ui/gfx/color_palette.h"
@@ -181,9 +180,7 @@
   content::WebContents* web_contents =
       delegate_->GetContentSettingWebContents();
   if (web_contents && !bubble_view_) {
-    views::View* anchor = this;
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-      anchor = parent();
+    views::View* const anchor = parent();
     bubble_view_ = new ContentSettingBubbleContents(
         content_setting_image_model_->CreateBubbleModel(
             delegate_->GetContentSettingBubbleModelDelegate(), web_contents,
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
index eea4e38..eca4ff4 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -14,7 +14,6 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/accessibility/view_accessibility.h"
 
@@ -82,16 +81,7 @@
 
 void LocationBarBubbleDelegateView::ShowForReason(DisplayReason reason) {
   if (reason == USER_GESTURE) {
-#if defined(OS_MACOSX)
-    // In the USER_GESTURE case, the icon will be in an active state so the
-    // bubble doesn't need an arrow (except on non-MD MacViews).
-    const bool hide_arrow =
-        ui::MaterialDesignController::IsSecondaryUiMaterial();
-#else
-    const bool hide_arrow = true;
-#endif
-    if (hide_arrow)
-      SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
+    SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
     GetWidget()->Show();
   } else {
     GetWidget()->ShowInactive();
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 07333fd..ba7286e1 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -360,9 +360,7 @@
 }
 
 views::View* LocationBarView::GetSecurityBubbleAnchorView() {
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-    return this;
-  return location_icon_view()->GetImageView();
+  return this;
 }
 
 bool LocationBarView::ShowPageInfoDialog(WebContents* contents) {
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index 7ddca684..6f92c7e6 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -34,7 +34,6 @@
 #include "extensions/browser/extension_zoom_request_client.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_features.h"
 #include "ui/gfx/favicon_size.h"
@@ -130,13 +129,8 @@
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   if (!is_fullscreen ||
       browser_view->immersive_mode_controller()->IsRevealed()) {
-    PageActionIconContainerView* container =
-        browser_view->toolbar_button_provider()
-            ->GetPageActionIconContainerView();
-    return ui::MaterialDesignController::IsSecondaryUiMaterial()
-               ? static_cast<views::View*>(container)
-               : static_cast<views::View*>(container->GetPageActionIconView(
-                     PageActionIconType::kZoom));
+    return browser_view->toolbar_button_provider()
+        ->GetPageActionIconContainerView();
   }
   return nullptr;
 #else  // OS_MACOSX && !MAC_VIEWS_BROWSER
diff --git a/chrome/browser/ui/views/page_info/chosen_object_view.cc b/chrome/browser/ui/views/page_info/chosen_object_view.cc
index 9e65981..8eda458 100644
--- a/chrome/browser/ui/views/page_info/chosen_object_view.cc
+++ b/chrome/browser/ui/views/page_info/chosen_object_view.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/resources/grit/ui_resources.h"
@@ -74,23 +73,11 @@
       PageInfoUI::GetChosenObjectIcon(*info_, false, label->enabled_color()));
   layout->AddView(label);
   // Create the delete button.
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    delete_button_ = views::CreateVectorImageButton(this);
-    views::SetImageFromVectorIcon(
-        delete_button_, vector_icons::kCloseRoundedIcon,
-        views::style::GetColor(*this, CONTEXT_BODY_TEXT_LARGE,
-                               views::style::STYLE_PRIMARY));
-
-  } else {
-    delete_button_ = new views::ImageButton(this);
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-    delete_button_->SetImage(views::ImageButton::STATE_NORMAL,
-                             rb.GetImageSkiaNamed(IDR_CLOSE_2));
-    delete_button_->SetImage(views::ImageButton::STATE_HOVERED,
-                             rb.GetImageSkiaNamed(IDR_CLOSE_2_H));
-    delete_button_->SetImage(views::ImageButton::STATE_PRESSED,
-                             rb.GetImageSkiaNamed(IDR_CLOSE_2_P));
-  }
+  delete_button_ = views::CreateVectorImageButton(this);
+  views::SetImageFromVectorIcon(
+      delete_button_, vector_icons::kCloseRoundedIcon,
+      views::style::GetColor(*this, CONTEXT_BODY_TEXT_LARGE,
+                             views::style::STYLE_PRIMARY));
   delete_button_->SetFocusForPlatform();
   delete_button_->set_request_focus_on_press(true);
   delete_button_->SetTooltipText(
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index 5c9f427..55ee18e6 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -43,7 +43,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/constants.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_features.h"
@@ -90,10 +89,6 @@
 constexpr int kMinBubbleWidth = 320;
 constexpr int kMaxBubbleWidth = 1000;
 
-bool UseHarmonyStyle() {
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
-
 SkColor GetRelatedTextColor() {
   views::Label label;
   return views::style::GetColor(label, views::style::CONTEXT_LABEL,
@@ -110,67 +105,6 @@
   column_set->AddPaddingColumn(views::GridLayout::kFixedSize, margin);
 }
 
-// Creates a section containing a title, icon, and link. Used to display Cookies
-// and Certificate information. Hovering over the |subtitle_text| will show the
-// |tooltip_text|.
-// *----------------------------------------------*
-// | Icon | Title |title_resource_id| string      |
-// |----------------------------------------------|
-// |      | Link |subtitle_text|                  |
-// *----------------------------------------------*
-views::View* CreateMoreInfoLinkSection(views::LinkListener* listener,
-                                       const gfx::ImageSkia& image_icon,
-                                       int title_resource_id,
-                                       const base::string16& subtitle_text,
-                                       int click_target_id,
-                                       const base::string16& tooltip_text,
-                                       views::Link** link) {
-  *link = new views::Link(subtitle_text);
-  (*link)->set_id(click_target_id);
-  (*link)->set_listener(listener);
-  (*link)->SetUnderline(false);
-  (*link)->SetTooltipText(tooltip_text);
-
-  views::View* new_view = new views::View();
-  views::GridLayout* layout =
-      new_view->SetLayoutManager(std::make_unique<views::GridLayout>(new_view));
-  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
-  const int side_margin =
-      provider->GetInsetsMetric(views::INSETS_DIALOG_SUBSECTION).left();
-  const int vert_spacing =
-      provider->GetDistanceMetric(DISTANCE_CONTROL_LIST_VERTICAL) / 2;
-
-  const int column = 0;
-  views::ColumnSet* column_set = layout->AddColumnSet(column);
-  column_set->AddPaddingColumn(views::GridLayout::kFixedSize, side_margin);
-  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
-                        views::GridLayout::kFixedSize, views::GridLayout::FIXED,
-                        PageInfoBubbleView::kIconColumnWidth, 0);
-  column_set->AddPaddingColumn(
-      views::GridLayout::kFixedSize,
-      provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL));
-  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL,
-                        views::GridLayout::kFixedSize,
-                        views::GridLayout::USE_PREF, 0, 0);
-  column_set->AddPaddingColumn(views::GridLayout::kFixedSize, side_margin);
-
-  layout->StartRowWithPadding(1.0, column, views::GridLayout::kFixedSize,
-                              vert_spacing);
-  views::ImageView* icon = new NonAccessibleImageView();
-  icon->SetImage(image_icon);
-  layout->AddView(icon);
-
-  views::Label* title_label = new views::Label(
-      l10n_util::GetStringUTF16(title_resource_id), CONTEXT_BODY_TEXT_LARGE);
-  layout->AddView(title_label);
-
-  layout->StartRow(1.0, column);
-  layout->SkipColumns(1);
-  layout->AddView(*link);
-  layout->AddPaddingRow(views::GridLayout::kFixedSize, vert_spacing);
-  return new_view;
-}
-
 // Formats strings and returns the |gfx::Range| of the newly inserted string.
 gfx::Range GetRangeForFormatString(int string_id,
                                    const base::string16& insert_string,
@@ -215,25 +149,11 @@
     PageInfoBubbleView* listener) {
   const base::string16& tooltip =
       l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_SETTINGS_TOOLTIP);
-  if (UseHarmonyStyle()) {
-    return CreateMoreInfoButton(
-        listener, PageInfoUI::GetSiteSettingsIcon(GetRelatedTextColor()),
-        IDS_PAGE_INFO_SITE_SETTINGS_LINK, base::string16(),
-        PageInfoBubbleView::VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_SITE_SETTINGS,
-        tooltip);
-  }
-  views::Link* site_settings_link = new views::Link(
-      l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_SETTINGS_LINK));
-  site_settings_link->set_id(
-      PageInfoBubbleView::VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_SITE_SETTINGS);
-  site_settings_link->SetTooltipText(tooltip);
-  site_settings_link->set_listener(listener);
-  site_settings_link->SetUnderline(false);
-  auto link_section = std::make_unique<views::View>();
-  link_section->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kHorizontal, gfx::Insets(0, side_margin)));
-  link_section->AddChildView(site_settings_link);
-  return link_section;
+  return CreateMoreInfoButton(
+      listener, PageInfoUI::GetSiteSettingsIcon(GetRelatedTextColor()),
+      IDS_PAGE_INFO_SITE_SETTINGS_LINK, base::string16(),
+      PageInfoBubbleView::VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_SITE_SETTINGS,
+      tooltip);
 }
 
 }  // namespace
@@ -510,7 +430,7 @@
 bool InternalPageInfoBubbleView::ShouldShowCloseButton() const {
   // TODO(patricialor): When Harmony is default, also remove |bubble_icon_| and
   // supporting code.
-  return ui::MaterialDesignController::IsSecondaryUiMaterial();
+  return true;
 }
 
 gfx::ImageSkia InternalPageInfoBubbleView::GetWindowIcon() {
@@ -566,7 +486,6 @@
       profile_(profile),
       header_(nullptr),
       site_settings_view_(nullptr),
-      cookie_link_legacy_(nullptr),
       cookie_button_(nullptr),
       weak_factory_(this) {
   // Capture the default bubble margin, and move it to the Layout classes. This
@@ -582,8 +501,7 @@
   // assuming that the "Cookies" & "Site settings" buttons will always be shown.
   const int hover_list_spacing =
       layout_provider->GetDistanceMetric(DISTANCE_CONTENT_LIST_VERTICAL_MULTI);
-  const int bottom_margin =
-      UseHarmonyStyle() ? hover_list_spacing : margins().bottom();
+  const int bottom_margin = hover_list_spacing;
   set_margins(gfx::Insets(margins().top(), 0, bottom_margin, 0));
 
   views::GridLayout* layout =
@@ -604,21 +522,14 @@
   layout->StartRow(views::GridLayout::kFixedSize, kColumnId);
   layout->AddView(new views::Separator());
 
-  // The views inside |site_settings_view_| have their own padding, so subtract
-  // that from the actual padding needed to get the correct value.
-  const int vertical_spacing =
-      layout_provider->GetDistanceMetric(
-          views::DISTANCE_UNRELATED_CONTROL_VERTICAL) -
-      layout_provider->GetDistanceMetric(DISTANCE_CONTROL_LIST_VERTICAL) / 2;
-  layout->StartRowWithPadding(
-      views::GridLayout::kFixedSize, kColumnId, views::GridLayout::kFixedSize,
-      UseHarmonyStyle() ? hover_list_spacing : vertical_spacing);
+  layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnId,
+                              views::GridLayout::kFixedSize,
+                              hover_list_spacing);
   site_settings_view_ = CreateSiteSettingsView();
   layout->AddView(site_settings_view_);
 
   layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnId,
-                              views::GridLayout::kFixedSize,
-                              UseHarmonyStyle() ? 0 : vertical_spacing);
+                              views::GridLayout::kFixedSize, 0);
   layout->AddView(CreateSiteSettingsLink(side_margin, this).release());
 
   views::BubbleDialogDelegateView::CreateBubble(this);
@@ -702,19 +613,13 @@
   }
 
   // Get the string to display the number of cookies.
-  base::string16 num_cookies_text;
-  if (UseHarmonyStyle()) {
-    num_cookies_text = l10n_util::GetPluralStringFUTF16(
-        IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED, total_allowed);
-  } else {
-    num_cookies_text = l10n_util::GetPluralStringFUTF16(
-        IDS_PAGE_INFO_NUM_COOKIES, total_allowed);
-  }
+  const base::string16 num_cookies_text = l10n_util::GetPluralStringFUTF16(
+      IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED, total_allowed);
 
-  // Create the cookie link / button if it doesn't yet exist. This method gets
-  // called each time site data is updated, so if it *does* already exist, skip
-  // this part and just update the text.
-  if (cookie_link_legacy_ == nullptr && cookie_button_ == nullptr) {
+  // Create the cookie button if it doesn't yet exist. This method gets called
+  // each time site data is updated, so if it *does* already exist, skip this
+  // part and just update the text.
+  if (cookie_button_ == nullptr) {
     // Get the icon.
     PageInfoUI::PermissionInfo info;
     info.type = CONTENT_SETTINGS_TYPE_COOKIES;
@@ -728,31 +633,19 @@
     const base::string16& tooltip =
         l10n_util::GetStringUTF16(IDS_PAGE_INFO_COOKIES_TOOLTIP);
 
-    if (UseHarmonyStyle()) {
-      cookie_button_ =
-          CreateMoreInfoButton(
-              this, icon, IDS_PAGE_INFO_COOKIES_BUTTON_TEXT, num_cookies_text,
-              VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_COOKIE_DIALOG, tooltip)
-              .release();
-      site_settings_view_->AddChildView(cookie_button_);
-    } else {
-      site_settings_view_->AddChildView(CreateMoreInfoLinkSection(
-          this, icon, IDS_PAGE_INFO_COOKIES, num_cookies_text,
-          VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_COOKIE_DIALOG, tooltip,
-          &cookie_link_legacy_));
-    }
+    cookie_button_ =
+        CreateMoreInfoButton(
+            this, icon, IDS_PAGE_INFO_COOKIES_BUTTON_TEXT, num_cookies_text,
+            VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_COOKIE_DIALOG, tooltip)
+            .release();
+    site_settings_view_->AddChildView(cookie_button_);
   }
 
   // Update the text displaying the number of allowed cookies.
-  DCHECK((cookie_link_legacy_ == nullptr) != (cookie_button_ == nullptr));
-  if (UseHarmonyStyle()) {
-    base::string16 button_text;
-    gfx::Range styled_range = GetRangeForFormatString(
-        IDS_PAGE_INFO_COOKIES_BUTTON_TEXT, num_cookies_text, &button_text);
-    cookie_button_->SetTitleTextWithHintRange(button_text, styled_range);
-  } else {
-    cookie_link_legacy_->SetText(num_cookies_text);
-  }
+  base::string16 button_text;
+  gfx::Range styled_range = GetRangeForFormatString(
+      IDS_PAGE_INFO_COOKIES_BUTTON_TEXT, num_cookies_text, &button_text);
+  cookie_button_->SetTitleTextWithHintRange(button_text, styled_range);
 
   Layout();
   SizeToContents();
@@ -846,24 +739,22 @@
     selector_rows_.push_back(std::move(selector));
   }
 
-  // In Harmony, ensure most comboboxes are the same width by setting them all
-  // to the widest combobox size, provided it does not exceed a maximum width.
+  // Ensure most comboboxes are the same width by setting them all to the widest
+  // combobox size, provided it does not exceed a maximum width.
   // For selected options that are over the maximum width, allow them to assume
   // their full width. If the combobox selection is changed, this may make the
   // widths inconsistent again, but that is OK since the widths will be updated
   // on the next time the bubble is opened.
-  if (UseHarmonyStyle()) {
-    const int maximum_width = ChromeLayoutProvider::Get()->GetDistanceMetric(
-        views::DISTANCE_BUTTON_MAX_LINKABLE_WIDTH);
-    int combobox_width = 0;
-    for (const auto& selector : selector_rows_) {
-      int curr_width = selector->GetComboboxWidth();
-      if (maximum_width >= curr_width)
-        combobox_width = std::max(combobox_width, curr_width);
+  const int maximum_width = ChromeLayoutProvider::Get()->GetDistanceMetric(
+      views::DISTANCE_BUTTON_MAX_LINKABLE_WIDTH);
+  int combobox_width = 0;
+  for (const auto& selector : selector_rows_) {
+    int curr_width = selector->GetComboboxWidth();
+    if (maximum_width >= curr_width)
+      combobox_width = std::max(combobox_width, curr_width);
     }
     for (const auto& selector : selector_rows_)
       selector->SetMinComboboxWidth(combobox_width);
-  }
 
   for (auto& object : chosen_object_info_list) {
     // Since chosen objects are presented after permissions in the same list,
@@ -890,7 +781,6 @@
   // Set the bubble title, update the title label text, then apply color.
   set_window_title(security_description->summary);
   GetBubbleFrameView()->UpdateWindowTitle();
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
     int text_style = views::style::STYLE_PRIMARY;
     switch (security_description->summary_style) {
       case SecuritySummaryColor::RED:
@@ -903,7 +793,6 @@
     static_cast<views::Label*>(GetBubbleFrameView()->title())
         ->SetEnabledColor(views::style::GetColor(
             *this, views::style::CONTEXT_DIALOG_TITLE, text_style));
-  }
 
   if (identity_info.certificate) {
     certificate_ = identity_info.certificate;
@@ -930,7 +819,6 @@
     // Add the Certificate Section.
     const gfx::ImageSkia icon =
         PageInfoUI::GetCertificateIcon(GetRelatedTextColor());
-    if (UseHarmonyStyle()) {
       const base::string16 secondary_text = l10n_util::GetStringUTF16(
           valid_identity ? IDS_PAGE_INFO_CERTIFICATE_VALID_PARENTHESIZED
                          : IDS_PAGE_INFO_CERTIFICATE_INVALID_PARENTHESIZED);
@@ -939,16 +827,6 @@
           VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_CERTIFICATE_VIEWER, tooltip);
       certificate_button->set_auto_compute_tooltip(false);
       site_settings_view_->AddChildView(certificate_button.release());
-    } else {
-      const base::string16 link_title = l10n_util::GetStringUTF16(
-          valid_identity ? IDS_PAGE_INFO_CERTIFICATE_VALID_LINK
-                         : IDS_PAGE_INFO_CERTIFICATE_INVALID_LINK);
-      views::Link* certificate_viewer_link = nullptr;
-      site_settings_view_->AddChildView(CreateMoreInfoLinkSection(
-          this, icon, IDS_PAGE_INFO_CERTIFICATE, link_title,
-          VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_CERTIFICATE_VIEWER, tooltip,
-          &certificate_viewer_link));
-    }
   }
 
   if (identity_info.show_change_password_buttons) {
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.h b/chrome/browser/ui/views/page_info/page_info_bubble_view.h
index 123b313..36c92711 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.h
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.h
@@ -164,9 +164,7 @@
   // The view that contains the certificate, cookie, and permissions sections.
   views::View* site_settings_view_;
 
-  // The link that opens the "Cookies" dialog. Non-harmony mode only.
-  views::Link* cookie_link_legacy_;
-  // The bubble that opens the "Cookies" dialog. Harmony mode only.
+  // The button that opens the "Cookies" dialog.
   HoverButton* cookie_button_;
 
   // The view that contains the "Permissions" table of the bubble.
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
index b37448c..d94af26 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -27,7 +27,6 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -78,16 +77,12 @@
   // Returns the number of cookies shown on the link or button to open the
   // collected cookies dialog. This should always be shown.
   base::string16 GetCookiesLinkText() {
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
       EXPECT_TRUE(view_->cookie_button_);
       ui::AXNodeData data;
       view_->cookie_button_->GetAccessibleNodeData(&data);
       std::string name;
       data.GetStringAttribute(ax::mojom::StringAttribute::kName, &name);
       return base::ASCIIToUTF16(name);
-    }
-    EXPECT_TRUE(view_->cookie_link_legacy_);
-    return view_->cookie_link_legacy_->text();
   }
 
   // Returns the permission label text of the |index|th permission selector row.
@@ -250,7 +245,6 @@
   // "set", so there is always one option checked in the resulting MenuModel.
   // This test creates settings that are left at their defaults, leading to zero
   // checked options, and checks that the text on the MenuButtons is right.
-  const bool is_md = ui::MaterialDesignController::IsSecondaryUiMaterial();
 
   PermissionInfoList list(1);
   list.back().type = CONTENT_SETTINGS_TYPE_GEOLOCATION;
@@ -281,31 +275,14 @@
 
   // Simulate a user selection via the UI. Note this will also cover logic in
   // PageInfo to update the pref.
-  if (is_md) {
-    // Under MD, the changed setting is always read from the combobox selected
-    // index when changed in the UI. PermissionSelectorRow::PermissionChanged()
-    // ignores the argument, except to detect whether it is the default.
-    api_->SimulateUserSelectingComboboxItemAt(0, 1);
-  } else {
-    list.back().setting = CONTENT_SETTING_ALLOW;
-    api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back());
-  }
+  api_->SimulateUserSelectingComboboxItemAt(0, 1);
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
   EXPECT_EQ(base::ASCIIToUTF16("Allow"), api_->GetPermissionButtonTextAt(0));
 
   // Setting to the default via the UI should keep the button around.
-  if (is_md) {
-    api_->SimulateUserSelectingComboboxItemAt(0, 0);
-    // Under MD, PermissionMenuModel gets strings using PageInfoUI::
-    // PermissionActionToUIString(..) rather than directly from the
-    // ResourceBundle.
-    EXPECT_EQ(base::ASCIIToUTF16("Ask (default)"),
-              api_->GetPermissionButtonTextAt(0));
-  } else {
-    list.back().setting = CONTENT_SETTING_ASK;
-    api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back());
-    EXPECT_EQ(base::ASCIIToUTF16("Ask"), api_->GetPermissionButtonTextAt(0));
-  }
+  api_->SimulateUserSelectingComboboxItemAt(0, 0);
+  EXPECT_EQ(base::ASCIIToUTF16("Ask (default)"),
+            api_->GetPermissionButtonTextAt(0));
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
 
   // However, since the setting is now default, recreating the dialog with those
@@ -364,8 +341,6 @@
   // "set", so there is always one option checked in the resulting MenuModel.
   // This test creates settings that are left at their defaults, leading to zero
   // checked options, and checks that the text on the MenuButtons is right.
-  const bool is_md = ui::MaterialDesignController::IsSecondaryUiMaterial();
-
   PermissionInfoList list(1);
   list.back().type = CONTENT_SETTINGS_TYPE_USB_GUARD;
   list.back().source = content_settings::SETTING_SOURCE_USER;
@@ -384,31 +359,14 @@
 
   // Simulate a user selection via the UI. Note this will also cover logic in
   // PageInfo to update the pref.
-  if (is_md) {
-    // Under MD, the changed setting is always read from the combobox selected
-    // index when changed in the UI. PermissionSelectorRow::PermissionChanged()
-    // ignores the argument, except to detect whether it is the default.
-    api_->SimulateUserSelectingComboboxItemAt(0, 2);
-  } else {
-    list.back().setting = CONTENT_SETTING_ASK;
-    api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back());
-  }
+  api_->SimulateUserSelectingComboboxItemAt(0, 2);
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
   EXPECT_EQ(base::ASCIIToUTF16("Ask"), api_->GetPermissionButtonTextAt(0));
 
   // Setting to the default via the UI should keep the button around.
-  if (is_md) {
     api_->SimulateUserSelectingComboboxItemAt(0, 0);
-    // Under MD, PermissionMenuModel gets strings using PageInfoUI::
-    // PermissionActionToUIString(..) rather than directly from the
-    // ResourceBundle.
     EXPECT_EQ(base::ASCIIToUTF16("Ask (default)"),
               api_->GetPermissionButtonTextAt(0));
-  } else {
-    list.back().setting = CONTENT_SETTING_ASK;
-    api_->GetPermissionSelectorAt(0)->PermissionChanged(list.back());
-    EXPECT_EQ(base::ASCIIToUTF16("Ask"), api_->GetPermissionButtonTextAt(0));
-  }
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
 
   // However, since the setting is now default, recreating the dialog with those
diff --git a/chrome/browser/ui/views/page_info/permission_selector_row.cc b/chrome/browser/ui/views/page_info/permission_selector_row.cc
index c4a535e..d0db13c 100644
--- a/chrome/browser/ui/views/page_info/permission_selector_row.cc
+++ b/chrome/browser/ui/views/page_info/permission_selector_row.cc
@@ -16,7 +16,6 @@
 #include "components/strings/grit/components_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/models/combobox_model.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image.h"
@@ -42,7 +41,7 @@
   const int list_item_padding = ChromeLayoutProvider::Get()->GetDistanceMetric(
                                     DISTANCE_CONTROL_LIST_VERTICAL) /
                                 2;
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial() || !has_reason)
+  if (!has_reason)
     return list_item_padding;
 
   const int combobox_height =
@@ -241,10 +240,8 @@
   set_listener(this);
   SetEnabled(enabled);
   UpdateSelectedIndex(use_default);
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    set_size_to_largest_label(false);
-    ModelChanged();
-  }
+  set_size_to_largest_label(false);
+  ModelChanged();
 }
 
 PermissionCombobox::~PermissionCombobox() {}
@@ -304,18 +301,8 @@
       base::Bind(&PermissionSelectorRow::PermissionChanged,
                  base::Unretained(this))));
 
-// Create the permission menu button.
-#if defined(OS_MACOSX)
-  bool use_real_combobox = true;
-#else
-  bool use_real_combobox =
-      ui::MaterialDesignController::IsSecondaryUiMaterial();
-#endif
-  if (use_real_combobox) {
-    InitializeComboboxView(layout, permission);
-  } else {
-    InitializeMenuButtonView(layout, permission);
-  }
+  // Create the permission menu button.
+  InitializeComboboxView(layout, permission);
 
   // Show the permission decision reason, if it was not the user.
   base::string16 reason =
@@ -337,15 +324,13 @@
     DCHECK(column_set);
     // Secondary labels in Harmony may not overlap into space shared with the
     // combobox column.
-    const int column_span =
-        ui::MaterialDesignController::IsSecondaryUiMaterial() ? 1 : 3;
+    const int column_span = 1;
 
-    // In Harmony, long labels that cannot fit in the existing space under the
-    // permission label should be allowed to use up to |kMaxSecondaryLabelWidth|
-    // for display.
+    // Long labels that cannot fit in the existing space under the permission
+    // label should be allowed to use up to |kMaxSecondaryLabelWidth| for
+    // display.
     constexpr int kMaxSecondaryLabelWidth = 140;
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial() &&
-        preferred_width > kMaxSecondaryLabelWidth) {
+    if (preferred_width > kMaxSecondaryLabelWidth) {
       layout->AddView(secondary_label, column_span, 1.0,
                       views::GridLayout::LEADING, views::GridLayout::CENTER,
                       kMaxSecondaryLabelWidth, 0);
@@ -384,23 +369,6 @@
   observer_list_.AddObserver(observer);
 }
 
-void PermissionSelectorRow::InitializeMenuButtonView(
-    views::GridLayout* layout,
-    const PageInfoUI::PermissionInfo& permission) {
-  bool button_enabled =
-      permission.source == content_settings::SETTING_SOURCE_USER;
-  menu_button_ = new internal::PermissionMenuButton(
-      PageInfoUI::PermissionActionToUIString(
-          profile_, permission.type, permission.setting,
-          permission.default_setting, permission.source),
-      menu_model_.get(), button_enabled);
-  menu_button_->SetEnabled(button_enabled);
-  menu_button_->SetTooltipText(l10n_util::GetStringFUTF16(
-      IDS_PAGE_INFO_SELECTOR_TOOLTIP,
-      PageInfoUI::PermissionTypeToUIString(permission.type)));
-  layout->AddView(menu_button_);
-}
-
 void PermissionSelectorRow::InitializeComboboxView(
     views::GridLayout* layout,
     const PageInfoUI::PermissionInfo& permission) {
diff --git a/chrome/browser/ui/views/page_info/permission_selector_row.h b/chrome/browser/ui/views/page_info/permission_selector_row.h
index 17ff487..2c9b6e8 100644
--- a/chrome/browser/ui/views/page_info/permission_selector_row.h
+++ b/chrome/browser/ui/views/page_info/permission_selector_row.h
@@ -67,8 +67,6 @@
  private:
   friend class test::PageInfoBubbleViewTestApi;
 
-  void InitializeMenuButtonView(views::GridLayout* layout,
-                                const PageInfoUI::PermissionInfo& permission);
   void InitializeComboboxView(views::GridLayout* layout,
                               const PageInfoUI::PermissionInfo& permission);
 
diff --git a/chrome/browser/ui/views/passwords/password_bubble_view_base.cc b/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
index 59c97b8d..0c8e4827b 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/views/passwords/password_items_view.h"
 #include "chrome/browser/ui/views/passwords/password_pending_view.h"
 #include "chrome/browser/ui/views/passwords/password_save_confirmation_view.h"
-#include "ui/base/material_design/material_design_controller.h"
 
 #if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -36,15 +35,8 @@
 
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   bool is_fullscreen = browser_view->IsFullscreen();
-  views::View* anchor_view = nullptr;
-  if (!is_fullscreen) {
-    if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-      anchor_view = browser_view->GetLocationBarView();
-    } else {
-      anchor_view =
-          browser_view->GetLocationBarView()->manage_passwords_icon_view();
-    }
-  }
+  views::View* const anchor_view =
+      is_fullscreen ? nullptr : browser_view->GetLocationBarView();
 
   PasswordBubbleViewBase* bubble =
       CreateBubble(web_contents, anchor_view, gfx::Point(), reason);
diff --git a/chrome/browser/ui/views/payments/modifiers_browsertest.cc b/chrome/browser/ui/views/payments/modifiers_browsertest.cc
index f15f6f8..92df460 100644
--- a/chrome/browser/ui/views/payments/modifiers_browsertest.cc
+++ b/chrome/browser/ui/views/payments/modifiers_browsertest.cc
@@ -93,7 +93,7 @@
   card.set_card_type(autofill::CreditCard::CardType::CARD_TYPE_CREDIT);
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { "
@@ -130,7 +130,7 @@
   card.set_card_type(autofill::CreditCard::CardType::CARD_TYPE_CREDIT);
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { "
@@ -167,7 +167,7 @@
   card.set_card_type(autofill::CreditCard::CardType::CARD_TYPE_CREDIT);
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { "
@@ -204,7 +204,7 @@
   card.set_card_type(autofill::CreditCard::CardType::CARD_TYPE_CREDIT);
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { "
@@ -263,7 +263,7 @@
   card.set_billing_address_id(profile.guid());
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { "
@@ -300,7 +300,7 @@
   card.set_billing_address_id(profile.guid());
   AddCreditCard(card);
 
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { document.getElementById('no_total').click(); })();";
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
index 379a722a..1c74e3b0 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -234,7 +234,7 @@
   PaymentRequestPaymentMethodIdentifierTest() {}
 
   void InvokePaymentRequestWithJs(const std::string& js) {
-    ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+    ResetEventWaiterForDialogOpened();
 
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), js));
 
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 7e07dd6..7662e41 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -254,7 +254,7 @@
 }
 
 void PaymentRequestBrowserTestBase::InvokePaymentRequestUI() {
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
 
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
@@ -767,6 +767,12 @@
       std::move(event_sequence));
 }
 
+void PaymentRequestBrowserTestBase::ResetEventWaiterForDialogOpened() {
+  ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                               DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                               DialogEvent::DIALOG_OPENED});
+}
+
 void PaymentRequestBrowserTestBase::WaitForObservedEvent() {
   event_waiter_->Wait();
 }
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
index 5377b9f..c270a2d6 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -253,6 +253,8 @@
   // Resets the event waiter for a given |event| or |event_sequence|.
   void ResetEventWaiter(DialogEvent event);
   void ResetEventWaiterForSequence(std::list<DialogEvent> event_sequence);
+  // Resets the event waiter for the events that trigger when opening a dialog.
+  void ResetEventWaiterForDialogOpened();
   // Wait for the event(s) passed to ResetEventWaiter*() to occur.
   void WaitForObservedEvent();
 
diff --git a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
index 79f0a2e0..199b31a7 100644
--- a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
@@ -39,6 +39,8 @@
     // the Payment Request is shown.
     ResetEventWaiterForSequence({DialogEvent::CAN_MAKE_PAYMENT_CALLED,
                                  DialogEvent::CAN_MAKE_PAYMENT_RETURNED,
+                                 DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
                                  DialogEvent::DIALOG_OPENED});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "queryShow();"));
     WaitForObservedEvent();
@@ -388,7 +390,7 @@
 
   // Start the Payment Request, CanMakePayment should not be called in this
   // test.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -430,7 +432,7 @@
 
   // Start the Payment Request, CanMakePayment should not be called in this
   // test.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -478,7 +480,7 @@
 
   // Start the Payment Request, CanMakePayment should not be called in this
   // test.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
diff --git a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
index d9dc0a4..13d7c2e 100644
--- a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
@@ -43,6 +43,8 @@
   // Payment Request is shown.
   ResetEventWaiterForSequence({DialogEvent::CAN_MAKE_PAYMENT_CALLED,
                                DialogEvent::CAN_MAKE_PAYMENT_RETURNED,
+                               DialogEvent::PROCESSING_SPINNER_SHOWN,
+                               DialogEvent::PROCESSING_SPINNER_HIDDEN,
                                DialogEvent::DIALOG_OPENED});
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "queryShow();"));
   WaitForObservedEvent();
@@ -80,7 +82,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -125,7 +127,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -172,7 +174,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -220,7 +222,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -262,7 +264,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -304,7 +306,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
@@ -348,7 +350,7 @@
   base::HistogramTester histogram_tester;
 
   // Start the Payment Request.
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "noQueryShow();"));
   WaitForObservedEvent();
 
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 6518308c..5d4f784a 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -83,6 +83,11 @@
   if (!request->state()->is_get_all_instruments_finished()) {
     request->state()->AddObserver(this);
     ShowProcessingSpinner();
+  } else if (observer_for_testing_) {
+    // When testing, signal that the processing spinner events have passed, even
+    // though the UI does not need to show it.
+    observer_for_testing_->OnProcessingSpinnerShown();
+    observer_for_testing_->OnProcessingSpinnerHidden();
   }
 
   ShowInitialPaymentSheet();
@@ -212,13 +217,16 @@
 
 void PaymentRequestDialogView::OnGetAllPaymentInstrumentsFinished() {
   HideProcessingSpinner();
-  if (observer_for_testing_) {
-    // The OnGetAllPaymentInstrumentsFinished() method is called if the payment
-    // instruments were retrieved asynchronously. This method hides the
-    // "Processing" spinner, so the UI is now ready for interaction. Any test
-    // that opens UI can now interact with it. The OnDialogOpened() call
-    // notifies the tests of this event.
-    observer_for_testing_->OnDialogOpened();
+  if (request_->state()->are_requested_methods_supported()) {
+    request_->RecordDialogShownEventInJourneyLogger();
+    if (observer_for_testing_) {
+      // The OnGetAllPaymentInstrumentsFinished() method is called if the
+      // payment instruments were retrieved asynchronously. This method hides
+      // the "Processing" spinner, so the UI is now ready for interaction. Any
+      // test that opens UI can now interact with it. The OnDialogOpened() call
+      // notifies the tests of this event.
+      observer_for_testing_->OnDialogOpened();
+    }
   }
 }
 
@@ -385,14 +393,16 @@
                             request_->spec(), request_->state(), this),
                         &controller_map_),
                     /* animate = */ false);
-  if (observer_for_testing_ &&
-      request_->state()->is_get_all_instruments_finished()) {
-    // The is_get_all_instruments_finished() method returns true if all payment
-    // instruments were retrieved synchronously. There's no "Processing" spinner
-    // to hide, so the UI is ready instantly. Any test that opens UI can now
-    // interact with it. The OnDialogOpened() call notifies the tests of this
-    // event.
-    observer_for_testing_->OnDialogOpened();
+  if (request_->state()->is_get_all_instruments_finished() &&
+      request_->state()->are_requested_methods_supported()) {
+    request_->RecordDialogShownEventInJourneyLogger();
+    if (observer_for_testing_) {
+      // The is_get_all_instruments_finished() method returns true if all
+      // payment instruments were retrieved synchronously. Any test that opens
+      // UI can now interact with it. The OnDialogOpened() call notifies the
+      // tests of this event.
+      observer_for_testing_->OnDialogOpened();
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
index 5964dc5..81074898 100644
--- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -97,7 +97,9 @@
   NavigateTo("/payment_request_bobpay_test.html");
   base::HistogramTester histogram_tester;
 
-  ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+  ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                               DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                               DialogEvent::NOT_SUPPORTED_ERROR});
   content::WebContents* web_contents = GetActiveWebContents();
   const std::string click_buy_button_js =
       "(function() { document.getElementById('buy').click(); })();";
@@ -1045,7 +1047,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   GURL iframe_url =
       https_server()->GetURL("b.com", "/payment_request_iframe.html");
-  ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+  ResetEventWaiterForDialogOpened();
   EXPECT_TRUE(content::NavigateIframeToURL(tab, "test", iframe_url));
   WaitForObservedEvent();
 
diff --git a/chrome/browser/ui/views/payments/payment_request_no_update_with_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_no_update_with_browsertest.cc
index 17212d8..69e0051 100644
--- a/chrome/browser/ui/views/payments/payment_request_no_update_with_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_no_update_with_browsertest.cc
@@ -18,7 +18,7 @@
 
   void RunJavaScriptFunctionToOpenPaymentRequestUI(
       const std::string& function_name) {
-    ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+    ResetEventWaiterForDialogOpened();
 
     content::WebContents* web_contents = GetActiveWebContents();
     ASSERT_TRUE(content::ExecuteScript(web_contents, function_name + "();"));
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
index ce79c34..8f7889f 100644
--- a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
@@ -172,7 +172,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -195,7 +197,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -332,7 +336,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -355,7 +361,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -382,7 +390,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -405,7 +415,9 @@
     // SetDownloaderAndIgnorePortInAppScopeForTesting again.
     SetDownloaderAndIgnorePortInAppScopeForTesting();
 
-    ResetEventWaiter(DialogEvent::NOT_SUPPORTED_ERROR);
+    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                                 DialogEvent::NOT_SUPPORTED_ERROR});
     ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
     WaitForObservedEvent();
     ExpectBodyContains({"NotSupportedError"});
@@ -462,7 +474,9 @@
     // Since the skip UI flow is available, the request will complete without
     // interaction besides hitting "pay" on the website.
     ResetEventWaiterForSequence(
-        {DialogEvent::DIALOG_OPENED, DialogEvent::DIALOG_CLOSED});
+        {DialogEvent::PROCESSING_SPINNER_SHOWN,
+         DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED,
+         DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
     content::WebContents* web_contents = GetActiveWebContents();
     const std::string click_buy_button_js =
         "(function() { document.getElementById('buy').click(); })();";
@@ -522,7 +536,7 @@
     // Since the skip UI flow is not available because the payer's email is
     // requested, the request will complete only after clicking on the Pay
     // button in the dialog.
-    ResetEventWaiter(DialogEvent::DIALOG_OPENED);
+    ResetEventWaiterForDialogOpened();
     content::WebContents* web_contents = GetActiveWebContents();
     const std::string click_buy_button_js =
         "(function() { "
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index c13f37f..63f572a 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -38,7 +38,6 @@
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
@@ -981,9 +980,8 @@
   views::StyledLabel::RangeStyleInfo link_style =
       views::StyledLabel::RangeStyleInfo::CreateForLink();
 
-  // This is the harmony color, so not needed when MD is default.
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-    link_style.override_color = gfx::kGoogleBlue700;
+  // TODO(pbos): Investigate whether this override is necessary.
+  link_style.override_color = gfx::kGoogleBlue700;
 
   data_source_label->AddStyleRange(
       gfx::Range(link_begin, link_begin + link_length), link_style);
diff --git a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
index 17546dd..30dc1a8 100644
--- a/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
+++ b/chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.cc
@@ -24,9 +24,8 @@
       is_browser_window_active_(is_browser_window_active) {}
 
 void TestChromePaymentRequestDelegate::ShowDialog(PaymentRequest* request) {
-  hidden_dialog_ =
-      std::make_unique<PaymentRequestDialogView>(request, observer_);
-  MaybeShowHiddenDialog(request);
+  shown_dialog_ = new PaymentRequestDialogView(request, observer_);
+  shown_dialog_->ShowDialog();
 }
 
 bool TestChromePaymentRequestDelegate::IsIncognito() const {
diff --git a/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc b/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
index 152d0d2..1cbd0e6c 100644
--- a/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/sad_tab_view_interactive_uitest.cc
@@ -19,7 +19,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/test/browser_test_utils.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/controls/button/blue_button.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/widget/widget.h"
@@ -82,10 +81,6 @@
   views::View* GetFocusedView() { return GetFocusManager()->GetFocusedView(); }
 
   const char* ActionButtonClassName() {
-#if defined(OS_CHROMEOS)
-    if (!ui::MaterialDesignController::IsSecondaryUiMaterial())
-      return views::BlueButton::kViewClassName;
-#endif
     return views::LabelButton::kViewClassName;
   }
 
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 012daf29..3f5f33e 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -386,6 +386,10 @@
   immersive_reveal_lock_.reset();
 }
 
+bool BrowserTabStripController::HasVisibleBackgroundTabShapes() const {
+  return GetFrameView()->HasVisibleBackgroundTabShapes();
+}
+
 SkColor BrowserTabStripController::GetFrameColor() const {
   return GetFrameView()->GetFrameColor();
 }
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index 7dcc9c0..db4e708 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -76,6 +76,7 @@
   bool ShouldDrawStrokes() const override;
   void OnStartedDraggingTabs() override;
   void OnStoppedDraggingTabs() override;
+  bool HasVisibleBackgroundTabShapes() const override;
   SkColor GetFrameColor() const override;
   SkColor GetToolbarTopSeparatorColor() const override;
   SkColor GetTabSeparatorColor() const override;
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index 06323d5..d1c60e2 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -150,6 +150,10 @@
 void FakeBaseTabStripController::OnStoppedDraggingTabs() {
 }
 
+bool FakeBaseTabStripController::HasVisibleBackgroundTabShapes() const {
+  return false;
+}
+
 SkColor FakeBaseTabStripController::GetFrameColor() const {
   return gfx::kPlaceholderColor;
 }
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index f7acb66..305dcdc0 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -52,6 +52,7 @@
   bool ShouldDrawStrokes() const override;
   void OnStartedDraggingTabs() override;
   void OnStoppedDraggingTabs() override;
+  bool HasVisibleBackgroundTabShapes() const override;
   SkColor GetFrameColor() const override;
   SkColor GetToolbarTopSeparatorColor() const override;
   SkColor GetTabSeparatorColor() const override;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index f618f280..34b35c69 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -536,8 +536,6 @@
   title_animation_.SetContainer(animation_container_.get());
 
   hover_controller_.SetAnimationContainer(animation_container_.get());
-
-  UpdateOpacities();
 }
 
 Tab::~Tab() {
@@ -852,7 +850,8 @@
 
 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
   mouse_hovered_ = true;
-  hover_controller_.SetSubtleOpacityScale(radial_highlight_opacity_);
+  hover_controller_.SetSubtleOpacityScale(
+      controller_->GetHoverOpacityForRadialHighlight());
   hover_controller_.Show(GlowHoverController::SUBTLE);
   Layout();
 }
@@ -968,7 +967,6 @@
 
 void Tab::OnThemeChanged() {
   OnButtonColorMaybeChanged();
-  UpdateOpacities();
 }
 
 void Tab::SetClosing(bool closing) {
@@ -1672,10 +1670,9 @@
     // narrow tabs will still stand out on the high end.
     const float range_start = float{GetStandardWidth()};
     const float range_end = float{GetMinimumInactiveWidth()};
-    const float value_in_range = float{bounds().width()};
+    const float value_in_range = float{width()};
     const float t = (value_in_range - range_start) / (range_end - range_start);
-    const float opacity = gfx::Tween::FloatValueBetween(
-        t * t, hover_opacity_min_, hover_opacity_max_);
+    const float opacity = controller_->GetHoverOpacityForTab(t * t);
     return is_selected ? (kSelectedTabThrobScale * opacity) : opacity;
   };
 
@@ -1710,45 +1707,6 @@
   }
 }
 
-void Tab::UpdateOpacities() {
-  // The contrast ratio for the hover effect on standard-width tabs.
-  // In the default Refresh color scheme, this corresponds to a hover
-  // opacity of 0.4.
-  constexpr float kDesiredContrastHoveredStandardWidthTab = 1.11f;
-
-  // The contrast ratio for the hover effect on min-width tabs.
-  // In the default Refresh color scheme, this corresponds to a hover
-  // opacity of 0.65.
-  constexpr float kDesiredContrastHoveredMinWidthTab = 1.19f;
-
-  // The contrast ratio for the radial gradient effect on hovered tabs.
-  // In the default Refresh color scheme, this corresponds to a hover
-  // opacity of 0.45.
-  constexpr float kDesiredContrastRadialGradient = 1.13728f;
-
-  const SkColor active_tab_bg_color =
-      controller_->GetTabBackgroundColor(TAB_ACTIVE);
-  const SkColor inactive_tab_bg_color =
-      controller_->GetTabBackgroundColor(TAB_INACTIVE);
-
-  const SkAlpha hover_base_alpha_wide =
-      color_utils::GetBlendValueWithMinimumContrast(
-          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
-          kDesiredContrastHoveredStandardWidthTab);
-  const SkAlpha hover_base_alpha_narrow =
-      color_utils::GetBlendValueWithMinimumContrast(
-          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
-          kDesiredContrastHoveredMinWidthTab);
-  const SkAlpha radial_highlight_alpha =
-      color_utils::GetBlendValueWithMinimumContrast(
-          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
-          kDesiredContrastRadialGradient);
-
-  hover_opacity_min_ = hover_base_alpha_wide / 255.0f;
-  hover_opacity_max_ = hover_base_alpha_narrow / 255.0f;
-  radial_highlight_opacity_ = radial_highlight_alpha / 255.0f;
-}
-
 void Tab::UpdateButtonIconColors(SkColor title_color) {
   // These ratios are calculated from the default colors specified in the
   // Material Refresh design document. Active/inactive are the contrast ratios
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index b893797..0c4999d2 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -310,9 +310,6 @@
   // state; it is the responsibility of the caller to request a paint.
   void UpdateTabIconNeedsAttentionBlocked();
 
-  // Computes and stores opacities derived from contrast ratios.
-  void UpdateOpacities();
-
   // Generate and update close button and alert icon colors for proper contrast.
   void UpdateButtonIconColors(SkColor title_color);
 
@@ -389,11 +386,6 @@
   // the view bounds.
   bool mouse_hovered_ = false;
 
-  // These computed values are stored for fast use during mouse moves & hover.
-  float hover_opacity_min_;
-  float hover_opacity_max_;
-  float radial_highlight_opacity_;
-
   class BackgroundCache {
    public:
     BackgroundCache();
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h
index b2d1753..0c0721d9 100644
--- a/chrome/browser/ui/views/tabs/tab_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -169,6 +169,14 @@
   // Returns the accessible tab name for this tab.
   virtual base::string16 GetAccessibleTabName(const Tab* tab) const = 0;
 
+  // Returns opacity for hover effect on a tab with |range_parameter| between
+  // 0 and 1, where 0 gives the minimum opacity suitable for wider tabs and 1
+  // gives maximum opacity suitable for narrower tabs.
+  virtual float GetHoverOpacityForTab(float range_parameter) const = 0;
+
+  // Returns opacity for use on tab hover radial highlight.
+  virtual float GetHoverOpacityForRadialHighlight() const = 0;
+
  protected:
   virtual ~TabController() {}
 };
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 4cfe393..efb69739 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -54,6 +54,7 @@
 #include "ui/display/screen.h"
 #include "ui/gfx/animation/animation_container.h"
 #include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size.h"
@@ -318,6 +319,7 @@
   for (int i = 0; i < tab_count(); ++i)
     tab_at(i)->FrameColorsChanged();
   new_tab_button_->FrameColorsChanged();
+  UpdateOpacities();
   SchedulePaint();
 }
 
@@ -343,10 +345,10 @@
   // draggability.  This region starts 1 DIP above the top of the separator.
   const int drag_handle_extension =
       (height() - Tab::GetTabSeparatorHeight()) / 2 - 1;
-  // TODO(pkasting): https://crbug.com/862276  Set this condition false when tab
-  // shapes are visible.
-  const bool extend_drag_handle =
-      MD::IsRefreshUi() && !SizeTabButtonToTopOfTabStrip();
+
+  // Disable drag handle extension when tab shapes are visible.
+  bool extend_drag_handle = !SizeTabButtonToTopOfTabStrip() &&
+                            !controller_->HasVisibleBackgroundTabShapes();
 
   // A hit on the tab is not in the caption unless it is in the thin strip
   // mentioned above.
@@ -1183,6 +1185,15 @@
   }
 }
 
+float TabStrip::GetHoverOpacityForTab(float range_parameter) const {
+  return gfx::Tween::FloatValueBetween(range_parameter, hover_opacity_min_,
+                                       hover_opacity_max_);
+}
+
+float TabStrip::GetHoverOpacityForRadialHighlight() const {
+  return radial_highlight_opacity_;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // TabStrip, views::View overrides:
 
@@ -1495,6 +1506,8 @@
     drop_indicator_width = drop_image->width();
     drop_indicator_height = drop_image->height();
   }
+
+  UpdateOpacities();
 }
 
 void TabStrip::StartInsertTabAnimation(int model_index) {
@@ -2047,6 +2060,48 @@
   }
 }
 
+void TabStrip::UpdateOpacities() {
+  // There may be no controller in unit tests, and call to GetTabBackgroundColor
+  // below requires one, so bail early if it is absent.
+  if (!controller_)
+    return;
+
+  // The contrast ratio for the hover effect on standard-width tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.4.
+  constexpr float kDesiredContrastHoveredStandardWidthTab = 1.11f;
+
+  // The contrast ratio for the hover effect on min-width tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.65.
+  constexpr float kDesiredContrastHoveredMinWidthTab = 1.19f;
+
+  // The contrast ratio for the radial gradient effect on hovered tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.45.
+  constexpr float kDesiredContrastRadialGradient = 1.13728f;
+
+  const SkColor active_tab_bg_color = GetTabBackgroundColor(TAB_ACTIVE);
+  const SkColor inactive_tab_bg_color = GetTabBackgroundColor(TAB_INACTIVE);
+
+  const SkAlpha hover_base_alpha_wide =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastHoveredStandardWidthTab);
+  const SkAlpha hover_base_alpha_narrow =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastHoveredMinWidthTab);
+  const SkAlpha radial_highlight_alpha =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastRadialGradient);
+
+  hover_opacity_min_ = hover_base_alpha_wide / 255.0f;
+  hover_opacity_max_ = hover_base_alpha_narrow / 255.0f;
+  radial_highlight_opacity_ = radial_highlight_alpha / 255.0f;
+}
+
 void TabStrip::ResizeLayoutTabs() {
   // We've been called back after the TabStrip has been emptied out (probably
   // just prior to the window being destroyed). We need to do nothing here or
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index de720eb..fe46944 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -262,6 +262,8 @@
   base::string16 GetAccessibleTabName(const Tab* tab) const override;
   int GetBackgroundResourceId(bool* has_custom_image) const override;
   gfx::Rect GetTabAnimationTargetBounds(const Tab* tab) override;
+  float GetHoverOpacityForTab(float range_parameter) const override;
+  float GetHoverOpacityForRadialHighlight() const override;
 
   // MouseWatcherListener:
   void MouseMovedOutOfHost() override;
@@ -454,6 +456,9 @@
   void UpdateStackedLayoutFromMouseEvent(views::View* source,
                                          const ui::MouseEvent& event);
 
+  // Computes and stores tab hover opacities derived from contrast ratios.
+  void UpdateOpacities();
+
   // -- Tab Resize Layout -----------------------------------------------------
 
   // Returns the current width of each tab. If the space for tabs is not evenly
@@ -674,6 +679,17 @@
   // updated to account for tab insertions/removals/moves.
   ui::ListSelectionModel selected_tabs_;
 
+  // When tabs are hovered, a radial highlight is shown and the tab opacity is
+  // adjusted using some value between |hover_opacity_min_| and
+  // |hover_opacity_max_| (depending on tab width). All these opacities depend
+  // on contrast ratios and are updated when colors or active state changes,
+  // so for efficiency's sake they are computed and stored once here instead
+  // of with each tab. Note: these defaults will be overwritten at construction
+  // except in cases where a unit test provides no controller_.
+  float hover_opacity_min_ = 1.0f;
+  float hover_opacity_max_ = 1.0f;
+  float radial_highlight_opacity_ = 1.0f;
+
   DISALLOW_COPY_AND_ASSIGN(TabStrip);
 };
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h
index 5bfb282c4..586cf72 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -119,6 +119,10 @@
   // from this tabstrip but the user is still dragging the tabs.
   virtual void OnStoppedDraggingTabs() = 0;
 
+  // Returns whether the shapes of background tabs are visible against the
+  // frame.
+  virtual bool HasVisibleBackgroundTabShapes() const = 0;
+
   // Returns the color of the browser frame, which is also the color of the
   // tabstrip background.
   virtual SkColor GetFrameColor() const = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 44eba68c..bdc135e2 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -102,6 +102,10 @@
   base::string16 GetAccessibleTabName(const Tab* tab) const override {
     return base::string16();
   }
+  float GetHoverOpacityForTab(float range_parameter) const override {
+    return 1.0f;
+  }
+  float GetHoverOpacityForRadialHighlight() const override { return 1.0f; }
 
  private:
   ui::ListSelectionModel selection_model_;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 6fe7e1b..3ffa012 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -308,14 +308,8 @@
     const GURL& url,
     bool already_bookmarked,
     bookmarks::BookmarkBubbleObserver* observer) {
-  views::View* anchor_view = location_bar();
+  views::View* const anchor_view = location_bar();
   PageActionIconView* const star_view = location_bar()->star_view();
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    if (star_view && star_view->visible())
-      anchor_view = star_view;
-    else
-      anchor_view = app_menu_button_;
-  }
 
   std::unique_ptr<BubbleSyncPromoDelegate> delegate;
   delegate.reset(new BookmarkBubbleSignInDelegate(browser_));
@@ -331,15 +325,9 @@
     translate::TranslateStep step,
     translate::TranslateErrors::Type error_type,
     bool is_user_gesture) {
-  views::View* anchor_view = location_bar();
+  views::View* const anchor_view = location_bar();
   PageActionIconView* translate_icon_view =
       location_bar()->translate_icon_view();
-  if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
-    if (translate_icon_view && translate_icon_view->visible())
-      anchor_view = translate_icon_view;
-    else
-      anchor_view = app_menu_button_;
-  }
 
   views::Widget* bubble_widget = TranslateBubbleView::ShowBubble(
       anchor_view, gfx::Point(), web_contents, step, error_type,
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index c1c363aa..40c22874 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -247,6 +247,8 @@
     "sample_queue.h",
     "service/browser_xr_runtime.cc",
     "service/browser_xr_runtime.h",
+    "service/isolated_device_provider.cc",
+    "service/isolated_device_provider.h",
     "service/vr_service_impl.cc",
     "service/vr_service_impl.h",
     "service/xr_device_impl.cc",
diff --git a/chrome/browser/vr/service/isolated_device_provider.cc b/chrome/browser/vr/service/isolated_device_provider.cc
new file mode 100644
index 0000000..2ca3095
--- /dev/null
+++ b/chrome/browser/vr/service/isolated_device_provider.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/service/isolated_device_provider.h"
+#include "content/public/common/service_manager_connection.h"
+#include "device/vr/buildflags/buildflags.h"
+#include "device/vr/isolated_gamepad_data_fetcher.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace vr {
+
+void IsolatedVRDeviceProvider::Initialize(
+    base::RepeatingCallback<void(device::mojom::XRDeviceId,
+                                 device::mojom::VRDisplayInfoPtr,
+                                 device::mojom::XRRuntimePtr)>
+        add_device_callback,
+    base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+        remove_device_callback,
+    base::OnceClosure initialization_complete) {
+  content::ServiceManagerConnection* connection =
+      content::ServiceManagerConnection::GetForProcess();
+  connection->GetConnector()->BindInterface(
+      device::mojom::kVrIsolatedServiceName,
+      mojo::MakeRequest(&device_provider_));
+
+  device::mojom::IsolatedXRRuntimeProviderClientPtr client;
+  binding_.Bind(mojo::MakeRequest(&client));
+  device_provider_->RequestDevices(std::move(client));
+
+  add_device_callback_ = std::move(add_device_callback);
+  remove_device_callback_ = std::move(remove_device_callback);
+  initialization_complete_ = std::move(initialization_complete);
+}
+
+bool IsolatedVRDeviceProvider::Initialized() {
+  return initialized_;
+}
+
+void IsolatedVRDeviceProvider::OnDeviceAdded(
+    device::mojom::XRRuntimePtr device,
+    device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory,
+    device::mojom::VRDisplayInfoPtr display_info) {
+  device::mojom::XRDeviceId id = display_info->id;
+  add_device_callback_.Run(id, std::move(display_info), std::move(device));
+
+#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
+  registered_gamepads_.insert(id);
+  device::IsolatedGamepadDataFetcher::Factory::AddGamepad(
+      id, std::move(gamepad_factory));
+#endif
+}
+
+void IsolatedVRDeviceProvider::OnDeviceRemoved(device::mojom::XRDeviceId id) {
+  remove_device_callback_.Run(id);
+
+#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
+  device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(id);
+#endif
+}
+
+void IsolatedVRDeviceProvider::OnDevicesEnumerated() {
+  initialized_ = true;
+  std::move(initialization_complete_).Run();
+}
+
+IsolatedVRDeviceProvider::IsolatedVRDeviceProvider() : binding_(this) {}
+
+IsolatedVRDeviceProvider::~IsolatedVRDeviceProvider() {
+#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
+  for (auto gamepad_id : registered_gamepads_) {
+    device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(gamepad_id);
+  }
+#endif
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/service/isolated_device_provider.h b/chrome/browser/vr/service/isolated_device_provider.h
new file mode 100644
index 0000000..ad059d19
--- /dev/null
+++ b/chrome/browser/vr/service/isolated_device_provider.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_SERVICE_ISOLATED_DEVICE_PROVIDER_H_
+#define CHROME_BROWSER_VR_SERVICE_ISOLATED_DEVICE_PROVIDER_H_
+
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "device/vr/vr_device.h"
+#include "device/vr/vr_device_provider.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace vr {
+
+class IsolatedVRDeviceProvider
+    : public device::VRDeviceProvider,
+      public device::mojom::IsolatedXRRuntimeProviderClient {
+ public:
+  IsolatedVRDeviceProvider();
+  ~IsolatedVRDeviceProvider() override;
+
+  // If the VR API requires initialization that should happen here.
+  void Initialize(base::RepeatingCallback<void(device::mojom::XRDeviceId,
+                                               device::mojom::VRDisplayInfoPtr,
+                                               device::mojom::XRRuntimePtr)>
+                      add_device_callback,
+                  base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+                      remove_device_callback,
+                  base::OnceClosure initialization_complete) override;
+
+  // Returns true if initialization is complete.
+  bool Initialized() override;
+
+ private:
+  // IsolatedXRRuntimeProviderClient
+  void OnDeviceAdded(
+      device::mojom::XRRuntimePtr device,
+      device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory,
+      device::mojom::VRDisplayInfoPtr display_info) override;
+  void OnDeviceRemoved(device::mojom::XRDeviceId id) override;
+  void OnDevicesEnumerated() override;
+
+  bool initialized_ = false;
+  device::mojom::IsolatedXRRuntimeProviderPtr device_provider_;
+
+  base::RepeatingCallback<void(device::mojom::XRDeviceId,
+                               device::mojom::VRDisplayInfoPtr,
+                               device::mojom::XRRuntimePtr)>
+      add_device_callback_;
+  base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+      remove_device_callback_;
+  base::OnceClosure initialization_complete_;
+  std::set<device::mojom::XRDeviceId> registered_gamepads_;
+  mojo::Binding<device::mojom::IsolatedXRRuntimeProviderClient> binding_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_SERVICE_ISOLATED_DEVICE_PROVIDER_H_
diff --git a/chrome/browser/vr/service/xr_runtime_manager.cc b/chrome/browser/vr/service/xr_runtime_manager.cc
index 4d92e1d..f4cca662 100644
--- a/chrome/browser/vr/service/xr_runtime_manager.cc
+++ b/chrome/browser/vr/service/xr_runtime_manager.cc
@@ -27,6 +27,12 @@
 #include "device/vr/android/gvr/gvr_device_provider.h"
 #endif
 
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+// We are hosting Oculus and OpenVR in a separate process
+#include "chrome/browser/vr/service/isolated_device_provider.h"
+#else
+// We are hosting Oculus and OpenVR in the browser process if enabled.
+
 #if BUILDFLAG(ENABLE_OPENVR)
 #include "device/vr/openvr/openvr_device_provider.h"
 #endif
@@ -35,6 +41,8 @@
 #include "device/vr/oculus/oculus_device_provider.h"
 #endif
 
+#endif  // BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+
 namespace vr {
 
 namespace {
@@ -56,6 +64,9 @@
     providers.emplace_back(std::make_unique<device::GvrDeviceProvider>());
 #endif
 
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+    providers.emplace_back(std::make_unique<vr::IsolatedVRDeviceProvider>());
+#else
 #if BUILDFLAG(ENABLE_OPENVR)
     if (base::FeatureList::IsEnabled(features::kOpenVR))
       providers.emplace_back(std::make_unique<device::OpenVRDeviceProvider>());
@@ -70,6 +81,7 @@
       providers.emplace_back(
           std::make_unique<device::OculusVRDeviceProvider>());
 #endif
+#endif  // ENABLE_ISOLATED_XR_SERVICE
 
     if (base::FeatureList::IsEnabled(features::kWebXrOrientationSensorDevice)) {
       content::ServiceManagerConnection* connection =
@@ -90,19 +102,19 @@
 
 BrowserXRRuntime* XRRuntimeManager::GetImmersiveRuntime() {
 #if defined(OS_ANDROID)
-  auto* gvr = GetRuntime(device::VRDeviceId::GVR_DEVICE_ID);
+  auto* gvr = GetRuntime(device::mojom::XRDeviceId::GVR_DEVICE_ID);
   if (gvr)
     return gvr;
 #endif
 
 #if BUILDFLAG(ENABLE_OPENVR)
-  auto* openvr = GetRuntime(device::VRDeviceId::OPENVR_DEVICE_ID);
+  auto* openvr = GetRuntime(device::mojom::XRDeviceId::OPENVR_DEVICE_ID);
   if (openvr)
     return openvr;
 #endif
 
 #if BUILDFLAG(ENABLE_OCULUS_VR)
-  auto* oculus = GetRuntime(device::VRDeviceId::OCULUS_DEVICE_ID);
+  auto* oculus = GetRuntime(device::mojom::XRDeviceId::OCULUS_DEVICE_ID);
   if (oculus)
     return oculus;
 #endif
@@ -110,8 +122,8 @@
   return nullptr;
 }
 
-BrowserXRRuntime* XRRuntimeManager::GetRuntime(device::VRDeviceId id) {
-  auto it = runtimes_.find(static_cast<unsigned int>(id));
+BrowserXRRuntime* XRRuntimeManager::GetRuntime(device::mojom::XRDeviceId id) {
+  auto it = runtimes_.find(id);
   if (it == runtimes_.end())
     return nullptr;
 
@@ -124,12 +136,12 @@
   if (options->immersive && !options->provide_passthrough_camera) {
     return GetImmersiveRuntime();
   } else if (options->provide_passthrough_camera && !options->immersive) {
-    return GetRuntime(device::VRDeviceId::ARCORE_DEVICE_ID);
+    return GetRuntime(device::mojom::XRDeviceId::ARCORE_DEVICE_ID);
   } else if (!options->provide_passthrough_camera && !options->immersive) {
     // Non immersive session.
     // Try the orientation provider if it exists.
     auto* orientation_runtime =
-        GetRuntime(device::VRDeviceId::ORIENTATION_DEVICE_ID);
+        GetRuntime(device::mojom::XRDeviceId::ORIENTATION_DEVICE_ID);
     if (orientation_runtime) {
       return orientation_runtime;
     }
@@ -180,7 +192,7 @@
   }
 }
 
-void XRRuntimeManager::AddRuntime(unsigned int id,
+void XRRuntimeManager::AddRuntime(device::mojom::XRDeviceId id,
                                   device::mojom::VRDisplayInfoPtr info,
                                   device::mojom::XRRuntimePtr runtime) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -192,7 +204,7 @@
     service->ConnectRuntime(runtimes_[id].get());
 }
 
-void XRRuntimeManager::RemoveRuntime(unsigned int id) {
+void XRRuntimeManager::RemoveRuntime(device::mojom::XRDeviceId id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto it = runtimes_.find(id);
   DCHECK(it != runtimes_.end());
@@ -207,7 +219,7 @@
 }
 
 void XRRuntimeManager::RecordVrStartupHistograms() {
-#if BUILDFLAG(ENABLE_OPENVR)
+#if BUILDFLAG(ENABLE_OPENVR) && !BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
   device::OpenVRDeviceProvider::RecordRuntimeAvailability();
 #endif
 }
@@ -253,7 +265,8 @@
   if (id == 0)
     return nullptr;
 
-  DeviceRuntimeMap::iterator iter = runtimes_.find(id);
+  DeviceRuntimeMap::iterator iter =
+      runtimes_.find(static_cast<device::mojom::XRDeviceId>(id));
   if (iter == runtimes_.end())
     return nullptr;
 
diff --git a/chrome/browser/vr/service/xr_runtime_manager.h b/chrome/browser/vr/service/xr_runtime_manager.h
index a59a4cd..3d1832705 100644
--- a/chrome/browser/vr/service/xr_runtime_manager.h
+++ b/chrome/browser/vr/service/xr_runtime_manager.h
@@ -59,6 +59,7 @@
   // Used by tests to supply providers.
   explicit XRRuntimeManager(ProviderList providers);
   // Used by tests to check on device state.
+  // TODO: Use XRDeviceId as appropriate.
   device::mojom::XRRuntime* GetRuntimeForTest(unsigned int id);
 
   size_t NumberOfConnectedServices();
@@ -68,19 +69,19 @@
   void OnProviderInitialized();
   bool AreAllProvidersInitialized();
 
-  void AddRuntime(unsigned int id,
+  void AddRuntime(device::mojom::XRDeviceId id,
                   device::mojom::VRDisplayInfoPtr info,
                   device::mojom::XRRuntimePtr runtime);
-  void RemoveRuntime(unsigned int id);
+  void RemoveRuntime(device::mojom::XRDeviceId id);
 
-  BrowserXRRuntime* GetRuntime(device::VRDeviceId id);
+  BrowserXRRuntime* GetRuntime(device::mojom::XRDeviceId id);
 
   ProviderList providers_;
 
   // VRDevices are owned by their providers, each correspond to a
   // BrowserXRRuntime that is owned by XRRuntimeManager.
   using DeviceRuntimeMap = base::small_map<
-      std::map<unsigned int, std::unique_ptr<BrowserXRRuntime>>>;
+      std::map<device::mojom::XRDeviceId, std::unique_ptr<BrowserXRRuntime>>>;
   DeviceRuntimeMap runtimes_;
 
   bool providers_initialized_ = false;
diff --git a/chrome/browser/vr/service/xr_runtime_manager_unittest.cc b/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
index 4452f459..4fa4963e 100644
--- a/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
+++ b/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
@@ -136,8 +136,8 @@
   auto service = BindService();
   EXPECT_EQ(1u, ServiceCount());
   EXPECT_TRUE(Provider()->Initialized());
-  device::FakeVRDevice* device = new device::FakeVRDevice(
-      static_cast<int>(device::VRDeviceId::ARCORE_DEVICE_ID));
+  device::FakeVRDevice* device =
+      new device::FakeVRDevice(device::mojom::XRDeviceId::ARCORE_DEVICE_ID);
   Provider()->AddDevice(base::WrapUnique(device));
 
   device::mojom::XRSessionOptions options = {};
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 336f4eae0..54f5379 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -19,6 +19,8 @@
     # those might be similar enough to merge.
     "web_app_icon_downloader.cc",
     "web_app_icon_downloader.h",
+    "web_app_icon_generator.cc",
+    "web_app_icon_generator.h",
     "web_app_shortcut.cc",
     "web_app_shortcut.h",
     "web_app_shortcut_chromeos.cc",
@@ -49,6 +51,7 @@
   sources = [
     "web_app_helpers_unittest.cc",
     "web_app_icon_downloader_unittest.cc",
+    "web_app_icon_generator_unittest.cc",
     "web_app_shortcut_mac_unittest.mm",
     "web_app_shortcut_unittest.cc",
   ]
diff --git a/chrome/browser/web_applications/components/pending_app_manager.h b/chrome/browser/web_applications/components/pending_app_manager.h
index 94191403..d69959d 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.h
+++ b/chrome/browser/web_applications/components/pending_app_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_PENDING_APP_MANAGER_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_PENDING_APP_MANAGER_H_
 
+#include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
@@ -21,7 +22,7 @@
 // should wait for the update request to finish before uninstalling the app.
 class PendingAppManager {
  public:
-  using InstallCallback = base::OnceCallback<void(bool)>;
+  using InstallCallback = base::OnceCallback<void(const std::string&)>;
 
   // How the app will be launched after installation.
   enum class LaunchContainer {
@@ -47,7 +48,9 @@
 
   // Queues an installation operation with the highest priority. Essentially
   // installing the app immediately if there are no ongoing operations or
-  // installing the app right after the current operation finishes.
+  // installing the app right after the current operation finishes. Runs its
+  // callback with the id of the installed app or an empty string if the
+  // installation fails.
   //
   // Fails if the same operation has been queued before. Should only be used in
   // response to a user action e.g. the user clicked an install button.
diff --git a/chrome/browser/web_applications/components/web_app_icon_generator.cc b/chrome/browser/web_applications/components/web_app_icon_generator.cc
new file mode 100644
index 0000000..ff330a7b
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_icon_generator.cc
@@ -0,0 +1,221 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_icon_generator.h"
+
+#include <cctype>
+#include <string>
+#include <utility>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "chrome/grit/platform_locale_settings.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "skia/ext/image_operations.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_analysis.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/image/canvas_image_source.h"
+#include "ui/gfx/image/image.h"
+
+namespace web_app {
+
+namespace {
+
+// Generates a square container icon of |output_size| by drawing the given
+// |letter| into a rounded background of |color|.
+class GeneratedIconImageSource : public gfx::CanvasImageSource {
+ public:
+  explicit GeneratedIconImageSource(char letter, SkColor color, int output_size)
+      : gfx::CanvasImageSource(gfx::Size(output_size, output_size), false),
+        letter_(letter),
+        color_(color),
+        output_size_(output_size) {}
+  ~GeneratedIconImageSource() override {}
+
+ private:
+  // gfx::CanvasImageSource overrides:
+  void Draw(gfx::Canvas* canvas) override {
+    const uint8_t kLumaThreshold = 190;
+    const int icon_size = output_size_ * 3 / 4;
+    const int icon_inset = output_size_ / 8;
+    const size_t border_radius = output_size_ / 16;
+    const size_t font_size = output_size_ * 7 / 16;
+
+    std::string font_name =
+        l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY);
+#if defined(OS_CHROMEOS)
+    const std::string kChromeOSFontFamily = "Noto Sans";
+    font_name = kChromeOSFontFamily;
+#endif
+
+    // Draw a rounded rect of the given |color|.
+    cc::PaintFlags background_flags;
+    background_flags.setAntiAlias(true);
+    background_flags.setColor(color_);
+
+    gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size);
+    canvas->DrawRoundRect(icon_rect, border_radius, background_flags);
+
+    // The text rect's size needs to be odd to center the text correctly.
+    gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1);
+    // Draw the letter onto the rounded rect. The letter's color depends on the
+    // luma of |color|.
+    const uint8_t luma = color_utils::GetLuma(color_);
+    canvas->DrawStringRectWithFlags(
+        base::string16(1, std::toupper(letter_)),
+        gfx::FontList(gfx::Font(font_name, font_size)),
+        (luma > kLumaThreshold) ? SK_ColorBLACK : SK_ColorWHITE, text_rect,
+        gfx::Canvas::TEXT_ALIGN_CENTER);
+  }
+
+  char letter_;
+
+  SkColor color_;
+
+  int output_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(GeneratedIconImageSource);
+};
+
+// Adds a square container icon of |output_size| and 2 * |output_size| pixels
+// to |bitmaps| by drawing the given |letter| into a rounded background of
+// |color|. For each size, if an icon of the requested size already exists in
+// |bitmaps|, nothing will happen.
+void GenerateIcon(std::map<int, BitmapAndSource>* bitmaps,
+                  int output_size,
+                  SkColor color,
+                  char letter) {
+  // Do nothing if there is already an icon of |output_size|.
+  if (bitmaps->count(output_size))
+    return;
+
+  (*bitmaps)[output_size].bitmap = GenerateBitmap(output_size, color, letter);
+}
+
+void GenerateIcons(std::set<int> generate_sizes,
+                   const GURL& app_url,
+                   SkColor generated_icon_color,
+                   std::map<int, BitmapAndSource>* bitmap_map) {
+  // The letter that will be painted on the generated icon.
+  char icon_letter = ' ';
+  std::string domain_and_registry(
+      net::registry_controlled_domains::GetDomainAndRegistry(
+          app_url,
+          net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
+  if (!domain_and_registry.empty()) {
+    icon_letter = domain_and_registry[0];
+  } else if (app_url.has_host()) {
+    icon_letter = app_url.host_piece()[0];
+  }
+
+  // If no color has been specified, use a dark gray so it will stand out on the
+  // black shelf.
+  if (generated_icon_color == SK_ColorTRANSPARENT)
+    generated_icon_color = SK_ColorDKGRAY;
+
+  for (int size : generate_sizes) {
+    GenerateIcon(bitmap_map, size, generated_icon_color, icon_letter);
+  }
+}
+
+}  // namespace
+
+BitmapAndSource::BitmapAndSource() {}
+
+BitmapAndSource::BitmapAndSource(const GURL& source_url_p,
+                                 const SkBitmap& bitmap_p)
+    : source_url(source_url_p), bitmap(bitmap_p) {}
+
+BitmapAndSource::~BitmapAndSource() {}
+
+std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
+    const std::vector<BitmapAndSource>& bitmaps,
+    const std::set<int>& sizes) {
+  std::map<int, BitmapAndSource> output_bitmaps;
+  std::map<int, BitmapAndSource> ordered_bitmaps;
+  for (const BitmapAndSource& bitmap_and_source : bitmaps) {
+    const SkBitmap& bitmap = bitmap_and_source.bitmap;
+    DCHECK(bitmap.width() == bitmap.height());
+    ordered_bitmaps[bitmap.width()] = bitmap_and_source;
+  }
+
+  if (ordered_bitmaps.size() > 0) {
+    for (const auto& size : sizes) {
+      // Find the closest not-smaller bitmap, or failing that use the largest
+      // icon available.
+      auto bitmaps_it = ordered_bitmaps.lower_bound(size);
+      if (bitmaps_it != ordered_bitmaps.end())
+        output_bitmaps[size] = bitmaps_it->second;
+      else
+        output_bitmaps[size] = ordered_bitmaps.rbegin()->second;
+
+      // Resize the bitmap if it does not exactly match the desired size.
+      if (output_bitmaps[size].bitmap.width() != size) {
+        output_bitmaps[size].bitmap = skia::ImageOperations::Resize(
+            output_bitmaps[size].bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
+            size, size);
+      }
+    }
+  }
+
+  return output_bitmaps;
+}
+
+SkBitmap GenerateBitmap(int output_size, SkColor color, char letter) {
+  gfx::ImageSkia icon_image(
+      std::make_unique<GeneratedIconImageSource>(letter, color, output_size),
+      gfx::Size(output_size, output_size));
+  SkBitmap dst;
+  if (dst.tryAllocPixels(icon_image.bitmap()->info())) {
+    icon_image.bitmap()->readPixels(dst.info(), dst.getPixels(), dst.rowBytes(),
+                                    0, 0);
+  }
+  return dst;
+}
+
+std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
+    const std::vector<BitmapAndSource>& icons,
+    const std::set<int>& sizes_to_generate,
+    const GURL& app_url,
+    SkColor* generated_icon_color) {
+  DCHECK(generated_icon_color);
+
+  // Resize provided icons to make sure we have versions for each size in
+  // |sizes_to_generate|.
+  std::map<int, BitmapAndSource> resized_bitmaps(
+      ConstrainBitmapsToSizes(icons, sizes_to_generate));
+
+  // Also add all provided icon sizes.
+  for (const BitmapAndSource& icon : icons) {
+    if (resized_bitmaps.find(icon.bitmap.width()) == resized_bitmaps.end())
+      resized_bitmaps.insert(std::make_pair(icon.bitmap.width(), icon));
+  }
+
+  // Determine the color that will be used for the icon's background. For this
+  // the dominant color of the first icon found is used.
+  if (resized_bitmaps.size()) {
+    color_utils::GridSampler sampler;
+    *generated_icon_color = color_utils::CalculateKMeanColorOfBitmap(
+        resized_bitmaps.begin()->second.bitmap);
+  }
+
+  // Work out what icons we need to generate here. Icons are only generated if
+  // there is no icon in the required size.
+  std::set<int> generate_sizes;
+  for (int size : sizes_to_generate) {
+    if (resized_bitmaps.find(size) == resized_bitmaps.end())
+      generate_sizes.insert(size);
+  }
+  GenerateIcons(generate_sizes, app_url, *generated_icon_color,
+                &resized_bitmaps);
+
+  return resized_bitmaps;
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_icon_generator.h b/chrome/browser/web_applications/components/web_app_icon_generator.h
new file mode 100644
index 0000000..11c8f72
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_icon_generator.h
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+struct BitmapAndSource {
+  BitmapAndSource();
+  BitmapAndSource(const GURL& source_url_p, const SkBitmap& bitmap_p);
+  ~BitmapAndSource();
+
+  GURL source_url;
+  SkBitmap bitmap;
+};
+
+// This finds the closest not-smaller bitmap in |bitmaps| for each size in
+// |sizes| and resizes it to that size. This returns a map of sizes to bitmaps
+// which contains only bitmaps of a size in |sizes| and at most one bitmap of
+// each size.
+std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
+    const std::vector<BitmapAndSource>& bitmaps,
+    const std::set<int>& sizes);
+
+// Generates a square container icon of |output_size| by drawing the given
+// |letter| into a rounded background of |color|.
+SkBitmap GenerateBitmap(int output_size, SkColor color, char letter);
+
+// Resize icons to the accepted sizes, and generate any that are missing.
+// Note that |app_url| is the launch URL for the app.
+// Output: |generated_icon_color| is the color to use if an icon needs to be
+// generated for the web app.
+std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
+    const std::vector<BitmapAndSource>& icons,
+    const std::set<int>& sizes_to_generate,
+    const GURL& app_url,
+    SkColor* generated_icon_color);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
diff --git a/chrome/browser/web_applications/components/web_app_icon_generator_unittest.cc b/chrome/browser/web_applications/components/web_app_icon_generator_unittest.cc
new file mode 100644
index 0000000..04b10922
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_icon_generator_unittest.cc
@@ -0,0 +1,422 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_icon_generator.h"
+
+#include <vector>
+
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace web_app {
+
+namespace {
+
+const char kAppIconURL1[] = "http://foo.com/1.png";
+const char kAppIconURL2[] = "http://foo.com/2.png";
+const char kAppIconURL3[] = "http://foo.com/3.png";
+
+// These sizes match extension_misc::ExtensionIcons enum.
+const int kIconSizeTiny = 16;
+const int kIconSizeSmall = 32;
+const int kIconSizeMedium = 48;
+const int kIconSizeLarge = 128;
+const int kIconSizeGigantor = 512;
+
+const int kIconSizeSmallBetweenMediumAndLarge = 63;
+const int kIconSizeLargeBetweenMediumAndLarge = 96;
+
+SkBitmap CreateSquareBitmapWithColor(int size, SkColor color) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(size, size);
+  bitmap.eraseColor(color);
+  return bitmap;
+}
+
+web_app::BitmapAndSource CreateSquareBitmapAndSourceWithColor(int size,
+                                                              SkColor color) {
+  return web_app::BitmapAndSource(GURL(),
+                                  CreateSquareBitmapWithColor(size, color));
+}
+
+struct IconInfo {
+  IconInfo() : width(0), height(0) {}
+  ~IconInfo() = default;
+
+  GURL url;
+  int width;
+  int height;
+  SkBitmap data;
+};
+
+IconInfo CreateIconInfoWithBitmap(int size, SkColor color) {
+  IconInfo icon_info;
+  icon_info.width = size;
+  icon_info.height = size;
+  icon_info.data = CreateSquareBitmapWithColor(size, color);
+  return icon_info;
+}
+
+std::set<int> TestSizesToGenerate() {
+  const int kIconSizesToGenerate[] = {
+      kIconSizeSmall, kIconSizeMedium, kIconSizeLarge,
+  };
+  return std::set<int>(kIconSizesToGenerate,
+                       kIconSizesToGenerate + base::size(kIconSizesToGenerate));
+}
+
+void ValidateAllIconsWithURLsArePresent(
+    const std::vector<IconInfo>& icons_to_check,
+    const std::map<int, BitmapAndSource>& size_map) {
+  EXPECT_EQ(icons_to_check.size(), size_map.size());
+
+  // Check that every icon with URL has a mapped icon.
+  for (const auto& icon : icons_to_check) {
+    if (!icon.url.is_empty()) {
+      bool found = false;
+      if (base::ContainsKey(size_map, icon.width)) {
+        const BitmapAndSource& mapped_icon = size_map.at(icon.width);
+        if (mapped_icon.source_url == icon.url &&
+            mapped_icon.bitmap.width() == icon.width) {
+          found = true;
+        }
+      }
+      EXPECT_TRUE(found);
+    }
+  }
+}
+
+std::vector<web_app::BitmapAndSource>::const_iterator
+FindLargestBitmapAndSourceVector(
+    const std::vector<web_app::BitmapAndSource>& bitmap_vector) {
+  auto result = bitmap_vector.end();
+  int largest = -1;
+  for (std::vector<web_app::BitmapAndSource>::const_iterator it =
+           bitmap_vector.begin();
+       it != bitmap_vector.end(); ++it) {
+    if (it->bitmap.width() > largest) {
+      result = it;
+    }
+  }
+  return result;
+}
+
+std::vector<web_app::BitmapAndSource>::const_iterator
+FindMatchingBitmapAndSourceVector(
+    const std::vector<web_app::BitmapAndSource>& bitmap_vector,
+    int size) {
+  for (std::vector<web_app::BitmapAndSource>::const_iterator it =
+           bitmap_vector.begin();
+       it != bitmap_vector.end(); ++it) {
+    if (it->bitmap.width() == size) {
+      return it;
+    }
+  }
+  return bitmap_vector.end();
+}
+
+std::vector<web_app::BitmapAndSource>::const_iterator
+FindEqualOrLargerBitmapAndSourceVector(
+    const std::vector<web_app::BitmapAndSource>& bitmap_vector,
+    int size) {
+  for (std::vector<web_app::BitmapAndSource>::const_iterator it =
+           bitmap_vector.begin();
+       it != bitmap_vector.end(); ++it) {
+    if (it->bitmap.width() >= size) {
+      return it;
+    }
+  }
+  return bitmap_vector.end();
+}
+
+void ValidateIconsGeneratedAndResizedCorrectly(
+    std::vector<web_app::BitmapAndSource> downloaded,
+    std::map<int, web_app::BitmapAndSource> size_map,
+    std::set<int> sizes_to_generate,
+    int expected_generated,
+    int expected_resized) {
+  GURL empty_url("");
+  int number_generated = 0;
+  int number_resized = 0;
+
+  auto icon_largest = FindLargestBitmapAndSourceVector(downloaded);
+  for (const auto& size : sizes_to_generate) {
+    auto icon_downloaded = FindMatchingBitmapAndSourceVector(downloaded, size);
+    auto icon_larger = FindEqualOrLargerBitmapAndSourceVector(downloaded, size);
+    if (icon_downloaded == downloaded.end()) {
+      auto icon_resized = size_map.find(size);
+      if (icon_largest == downloaded.end()) {
+        // There are no downloaded icons. Expect an icon to be generated.
+        EXPECT_NE(size_map.end(), icon_resized);
+        EXPECT_EQ(size, icon_resized->second.bitmap.width());
+        EXPECT_EQ(size, icon_resized->second.bitmap.height());
+        EXPECT_EQ(size, icon_resized->second.bitmap.height());
+        EXPECT_EQ(empty_url, icon_resized->second.source_url);
+        ++number_generated;
+      } else {
+        // If there is a larger downloaded icon, it should be resized. Otherwise
+        // the largest downloaded icon should be resized.
+        auto icon_to_resize = icon_largest;
+        if (icon_larger != downloaded.end())
+          icon_to_resize = icon_larger;
+        EXPECT_NE(size_map.end(), icon_resized);
+        EXPECT_EQ(size, icon_resized->second.bitmap.width());
+        EXPECT_EQ(size, icon_resized->second.bitmap.height());
+        EXPECT_EQ(size, icon_resized->second.bitmap.height());
+        EXPECT_EQ(icon_to_resize->source_url, icon_resized->second.source_url);
+        ++number_resized;
+      }
+    } else {
+      // There is an icon of exactly this size downloaded. Expect no icon to be
+      // generated, and the existing downloaded icon to be used.
+      auto icon_resized = size_map.find(size);
+      EXPECT_NE(size_map.end(), icon_resized);
+      EXPECT_EQ(size, icon_resized->second.bitmap.width());
+      EXPECT_EQ(size, icon_resized->second.bitmap.height());
+      EXPECT_EQ(size, icon_downloaded->bitmap.width());
+      EXPECT_EQ(size, icon_downloaded->bitmap.height());
+      EXPECT_EQ(icon_downloaded->source_url, icon_resized->second.source_url);
+    }
+  }
+  EXPECT_EQ(expected_generated, number_generated);
+  EXPECT_EQ(expected_resized, number_resized);
+}
+
+void ValidateBitmapSizeAndColor(SkBitmap bitmap, int size, SkColor color) {
+  // Obtain pixel lock to access pixels.
+  EXPECT_EQ(color, bitmap.getColor(0, 0));
+  EXPECT_EQ(size, bitmap.width());
+  EXPECT_EQ(size, bitmap.height());
+}
+
+void TestIconGeneration(int icon_size,
+                        int expected_generated,
+                        int expected_resized) {
+  std::vector<BitmapAndSource> downloaded;
+
+  // Add an icon with a URL and bitmap. 'Download' it.
+  IconInfo icon_info = CreateIconInfoWithBitmap(icon_size, SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL1);
+  downloaded.push_back(BitmapAndSource(icon_info.url, icon_info.data));
+
+  // Now run the resizing/generation and validation.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, TestSizesToGenerate(), GURL(),
+                                    &generated_icon_color);
+
+  ValidateIconsGeneratedAndResizedCorrectly(
+      downloaded, size_map, TestSizesToGenerate(), expected_generated,
+      expected_resized);
+}
+
+}  // namespace
+
+TEST(WebAppIconGeneratorTest, ConstrainBitmapsToSizes) {
+  std::set<int> desired_sizes;
+  desired_sizes.insert(16);
+  desired_sizes.insert(32);
+  desired_sizes.insert(48);
+  desired_sizes.insert(96);
+  desired_sizes.insert(128);
+  desired_sizes.insert(256);
+
+  {
+    std::vector<web_app::BitmapAndSource> bitmaps;
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(16, SK_ColorRED));
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(32, SK_ColorGREEN));
+    bitmaps.push_back(
+        CreateSquareBitmapAndSourceWithColor(144, SK_ColorYELLOW));
+
+    std::map<int, web_app::BitmapAndSource> results(
+        ConstrainBitmapsToSizes(bitmaps, desired_sizes));
+
+    EXPECT_EQ(6u, results.size());
+    ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorRED);
+    ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorGREEN);
+    ValidateBitmapSizeAndColor(results[48].bitmap, 48, SK_ColorYELLOW);
+    ValidateBitmapSizeAndColor(results[96].bitmap, 96, SK_ColorYELLOW);
+    ValidateBitmapSizeAndColor(results[128].bitmap, 128, SK_ColorYELLOW);
+    ValidateBitmapSizeAndColor(results[256].bitmap, 256, SK_ColorYELLOW);
+  }
+  {
+    std::vector<web_app::BitmapAndSource> bitmaps;
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(512, SK_ColorRED));
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(18, SK_ColorGREEN));
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(33, SK_ColorBLUE));
+    bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(17, SK_ColorYELLOW));
+
+    std::map<int, web_app::BitmapAndSource> results(
+        ConstrainBitmapsToSizes(bitmaps, desired_sizes));
+
+    EXPECT_EQ(6u, results.size());
+    ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorYELLOW);
+    ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorBLUE);
+    ValidateBitmapSizeAndColor(results[48].bitmap, 48, SK_ColorRED);
+    ValidateBitmapSizeAndColor(results[96].bitmap, 96, SK_ColorRED);
+    ValidateBitmapSizeAndColor(results[128].bitmap, 128, SK_ColorRED);
+    ValidateBitmapSizeAndColor(results[256].bitmap, 256, SK_ColorRED);
+  }
+}
+
+TEST(WebAppIconGeneratorTest, LinkedAppIconsAreNotChanged) {
+  std::vector<IconInfo> icons_info;
+
+  IconInfo icon_info;
+  icon_info.url = GURL(kAppIconURL3);
+
+  icon_info.width = kIconSizeMedium;
+  icons_info.push_back(icon_info);
+
+  icon_info.width = kIconSizeSmall;
+  icons_info.push_back(icon_info);
+
+  icon_info.width = kIconSizeLarge;
+  icons_info.push_back(icon_info);
+
+  // 'Download' one of the icons without a size or bitmap.
+  std::vector<BitmapAndSource> downloaded;
+  downloaded.push_back(BitmapAndSource(
+      GURL(kAppIconURL3),
+      CreateSquareBitmapWithColor(kIconSizeLarge, SK_ColorBLACK)));
+
+  const auto& sizes = TestSizesToGenerate();
+
+  // Now run the resizing and generation into a new web icons info.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, sizes, GURL(),
+                                    &generated_icon_color);
+  EXPECT_EQ(sizes.size(), size_map.size());
+
+  // Now check that the linked app icons (i.e. those with URLs) are matching.
+  ValidateAllIconsWithURLsArePresent(icons_info, size_map);
+}
+
+TEST(WebAppIconGeneratorTest, IconsResizedFromOddSizes) {
+  std::vector<BitmapAndSource> downloaded;
+
+  // Add three icons with a URL and bitmap. 'Download' each of them.
+  IconInfo icon_info = CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL1);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeSmallBetweenMediumAndLarge,
+                                       SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL2);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeLargeBetweenMediumAndLarge,
+                                       SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL3);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  // Now run the resizing and generation.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, TestSizesToGenerate(), GURL(),
+                                    &generated_icon_color);
+
+  // No icons should be generated. The LARGE and MEDIUM sizes should be resized.
+  ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
+                                            TestSizesToGenerate(), 0, 2);
+}
+
+TEST(WebAppIconGeneratorTest, IconsResizedFromLarger) {
+  std::vector<web_app::BitmapAndSource> downloaded;
+
+  // Add three icons with a URL and bitmap. 'Download' two of them and pretend
+  // the third failed to download.
+  IconInfo icon_info = CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL1);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorBLUE);
+  icon_info.url = GURL(kAppIconURL2);
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
+  icon_info.url = GURL(kAppIconURL3);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  // Now run the resizing and generation.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, TestSizesToGenerate(), GURL(),
+                                    &generated_icon_color);
+
+  // Expect icon for MEDIUM and LARGE to be resized from the gigantor icon
+  // as it was not downloaded.
+  ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
+                                            TestSizesToGenerate(), 0, 2);
+}
+
+TEST(WebAppIconGeneratorTest, AllIconsGeneratedWhenNotDownloaded) {
+  std::vector<web_app::BitmapAndSource> downloaded;
+
+  // Add three icons with a URL and bitmap. 'Download' none of them.
+  IconInfo icon_info = CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL1);
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorBLUE);
+  icon_info.url = GURL(kAppIconURL2);
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
+  icon_info.url = GURL(kAppIconURL3);
+
+  // Now run the resizing and generation.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, TestSizesToGenerate(), GURL(),
+                                    &generated_icon_color);
+
+  // Expect all icons to be generated.
+  ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
+                                            TestSizesToGenerate(), 3, 0);
+}
+
+TEST(WebAppIconGeneratorTest, IconResizedFromLargerAndSmaller) {
+  std::vector<web_app::BitmapAndSource> downloaded;
+
+  // Pretend the huge icon wasn't downloaded but two smaller ones were.
+  IconInfo icon_info = CreateIconInfoWithBitmap(kIconSizeTiny, SK_ColorRED);
+  icon_info.url = GURL(kAppIconURL1);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeMedium, SK_ColorBLUE);
+  icon_info.url = GURL(kAppIconURL2);
+  downloaded.push_back(web_app::BitmapAndSource(icon_info.url, icon_info.data));
+
+  icon_info = CreateIconInfoWithBitmap(kIconSizeGigantor, SK_ColorBLACK);
+  icon_info.url = GURL(kAppIconURL3);
+
+  // Now run the resizing and generation.
+  SkColor generated_icon_color;
+  std::map<int, web_app::BitmapAndSource> size_map =
+      ResizeIconsAndGenerateMissing(downloaded, TestSizesToGenerate(), GURL(),
+                                    &generated_icon_color);
+
+  // Expect no icons to be generated, but the LARGE and SMALL icons to be
+  // resized from the MEDIUM icon.
+  ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
+                                            TestSizesToGenerate(), 0, 2);
+
+  // Verify specifically that the LARGE icons was resized from the medium icon.
+  const auto it = size_map.find(kIconSizeLarge);
+  EXPECT_NE(size_map.end(), it);
+  EXPECT_EQ(GURL(kAppIconURL2), it->second.source_url);
+}
+
+TEST(WebAppIconGeneratorTest, IconsResizedWhenOnlyATinyOneIsProvided) {
+  // When only a tiny icon is downloaded (smaller than the three desired
+  // sizes), 3 icons should be resized.
+  TestIconGeneration(kIconSizeTiny, 0, 3);
+}
+
+TEST(WebAppIconGeneratorTest, IconsResizedWhenOnlyAGigantorOneIsProvided) {
+  // When an enormous icon is provided, each desired icon size should be resized
+  // from it, and no icons should be generated.
+  TestIconGeneration(kIconSizeGigantor, 0, 3);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
index 69317aa..2521c2b2 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -14,6 +14,16 @@
 
 namespace extensions {
 
+BookmarkAppInstallationTask::Result::Result(ResultCode code,
+                                            const std::string& app_id)
+    : code(code), app_id(app_id) {
+  DCHECK_EQ(code == ResultCode::kSuccess, !app_id.empty());
+}
+
+BookmarkAppInstallationTask::Result::Result(Result&&) = default;
+
+BookmarkAppInstallationTask::Result::~Result() = default;
+
 BookmarkAppInstallationTask::~BookmarkAppInstallationTask() = default;
 
 void BookmarkAppInstallationTask::SetDataRetrieverForTesting(
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
index ed515370..837c6aa 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_INSTALLATION_TASK_H_
 
 #include <memory>
+#include <string>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
@@ -21,12 +22,24 @@
 // or WebApplicationInfo. Can only be called from the UI thread.
 class BookmarkAppInstallationTask {
  public:
-  enum class Result {
+  enum class ResultCode {
     kSuccess,
     kGetWebApplicationInfoFailed,
     kInstallationFailed,
   };
 
+  struct Result {
+    Result(ResultCode code, const std::string& app_id);
+    Result(Result&&);
+    ~Result();
+
+    const ResultCode code;
+    // Empty unless |code| is ResultCode::kSuccess.
+    std::string app_id;
+
+    DISALLOW_COPY_AND_ASSIGN(Result);
+  };
+
   using ResultCallback = base::OnceCallback<void(Result)>;
 
   virtual ~BookmarkAppInstallationTask();
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
index a871b404..e90e157 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -23,11 +23,15 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/web_contents_tester.h"
+#include "extensions/common/extension_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 
 namespace extensions {
 
+using Result = BookmarkAppInstallationTask::Result;
+using ResultCode = BookmarkAppInstallationTask::ResultCode;
+
 namespace {
 
 const char kWebAppUrl[] = "https://foo.example";
@@ -40,9 +44,8 @@
   BookmarkAppInstallationTaskTest() = default;
   ~BookmarkAppInstallationTaskTest() override = default;
 
-  void OnInstallationTaskResult(base::OnceClosure quit_closure,
-                                BookmarkAppInstallationTask::Result result) {
-    app_installation_result_ = result;
+  void OnInstallationTaskResult(base::OnceClosure quit_closure, Result result) {
+    app_installation_result_ = std::make_unique<Result>(std::move(result));
     std::move(quit_closure).Run();
   }
 
@@ -59,16 +62,15 @@
 
  protected:
   bool app_installed() {
-    return app_installation_result_.value() ==
-           BookmarkAppInstallationTask::Result::kSuccess;
+    bool app_installed = app_installation_result_->code == ResultCode::kSuccess;
+    EXPECT_NE(app_installed, app_installation_result_->app_id.empty());
+    return app_installed;
   }
 
-  BookmarkAppInstallationTask::Result app_installation_result() {
-    return app_installation_result_.value();
-  }
+  const Result& app_installation_result() { return *app_installation_result_; }
 
  private:
-  base::Optional<BookmarkAppInstallationTask::Result> app_installation_result_;
+  std::unique_ptr<Result> app_installation_result_;
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallationTaskTest);
 };
@@ -115,13 +117,14 @@
                ResultCallback callback) override {
     web_app_info_ = web_app_info;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), succeeds_));
+        FROM_HERE, base::BindOnce(std::move(callback),
+                                  succeeds_ ? "12345" : std::string()));
   }
 
   const WebApplicationInfo& web_app_info() { return web_app_info_.value(); }
 
  private:
-  bool succeeds_;
+  const bool succeeds_;
   base::Optional<WebApplicationInfo> web_app_info_;
 
   DISALLOW_COPY_AND_ASSIGN(TestInstaller);
@@ -156,8 +159,9 @@
   run_loop.Run();
 
   EXPECT_FALSE(app_installed());
-  EXPECT_EQ(BookmarkAppInstallationTask::Result::kGetWebApplicationInfoFailed,
-            app_installation_result());
+  EXPECT_EQ(
+      BookmarkAppInstallationTask::ResultCode::kGetWebApplicationInfoFailed,
+      app_installation_result().code);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest, ShortcutFromContents_NoManifest) {
@@ -208,8 +212,8 @@
   run_loop.Run();
 
   EXPECT_FALSE(app_installed());
-  EXPECT_EQ(BookmarkAppInstallationTask::Result::kInstallationFailed,
-            app_installation_result());
+  EXPECT_EQ(BookmarkAppInstallationTask::ResultCode::kInstallationFailed,
+            app_installation_result().code);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installer.cc b/chrome/browser/web_applications/extensions/bookmark_app_installer.cc
index 7a504a8..7f911b4 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installer.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installer.cc
@@ -10,7 +10,10 @@
 #include "base/callback.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/web_application_info.h"
+#include "extensions/common/extension.h"
+#include "url/gurl.h"
 
 namespace extensions {
 
@@ -22,9 +25,9 @@
 
 void BookmarkAppInstaller::Install(const WebApplicationInfo& web_app_info,
                                    ResultCallback callback) {
-  crx_installer_->set_installer_callback(
-      base::BindOnce(&BookmarkAppInstaller::OnInstall,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  crx_installer_->set_installer_callback(base::BindOnce(
+      &BookmarkAppInstaller::OnInstall, weak_ptr_factory_.GetWeakPtr(),
+      std::move(callback), web_app_info.app_url));
   crx_installer_->InstallWebApp(web_app_info);
 }
 
@@ -35,11 +38,18 @@
 
 void BookmarkAppInstaller::OnInstall(
     ResultCallback callback,
+    const GURL& app_url,
     const base::Optional<CrxInstallError>& error) {
-  // TODO(crbug.com/864904): Finish the installation i.e. set launch container.
+  if (error) {
+    std::move(callback).Run(std::string());
+    return;
+  }
 
-  const bool installation_succeeded = !error;
-  std::move(callback).Run(installation_succeeded);
+  auto* installed_extension = crx_installer_->extension();
+  DCHECK(installed_extension);
+  DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(installed_extension), app_url);
+
+  std::move(callback).Run(installed_extension->id());
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installer.h b/chrome/browser/web_applications/extensions/bookmark_app_installer.h
index 32aa0b7..a9334c4 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installer.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installer.h
@@ -10,7 +10,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "extensions/common/extension_id.h"
 
+class GURL;
 class Profile;
 
 struct WebApplicationInfo;
@@ -24,7 +26,7 @@
 // App in the system.
 class BookmarkAppInstaller {
  public:
-  using ResultCallback = base::OnceCallback<void(bool)>;
+  using ResultCallback = base::OnceCallback<void(const ExtensionId&)>;
 
   // Constructs a BookmarkAppInstaller that will install the Bookmark App in
   // |profile|.
@@ -40,6 +42,7 @@
 
  private:
   void OnInstall(ResultCallback callback,
+                 const GURL& app_url,
                  const base::Optional<CrxInstallError>& error);
 
   scoped_refptr<CrxInstaller> crx_installer_;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installer_unittest.cc
index 73b42b6..915b6b2f 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installer_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installer_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "extensions/browser/install/crx_install_error.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -82,8 +83,9 @@
                                         false /* autoupdate_enabled */);
   }
 
-  void InstallCallback(base::OnceClosure quit_closure, bool app_installed) {
-    app_installed_ = app_installed;
+  void InstallCallback(base::OnceClosure quit_closure,
+                       const ExtensionId& extension_id) {
+    app_installed_ = !extension_id.empty();
     std::move(quit_closure).Run();
   }
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
index e71f589..e2f117b6 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -41,7 +42,8 @@
     std::unique_ptr<WebApplicationInfo> web_app_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!web_app_info) {
-    std::move(result_callback).Run(Result::kGetWebApplicationInfoFailed);
+    std::move(result_callback)
+        .Run(Result(ResultCode::kGetWebApplicationInfoFailed, std::string()));
     return;
   }
 
@@ -76,9 +78,10 @@
 
 void BookmarkAppShortcutInstallationTask::OnInstalled(
     ResultCallback result_callback,
-    bool success) {
-  std::move(result_callback)
-      .Run(success ? Result::kSuccess : Result::kInstallationFailed);
+    const std::string& app_id) {
+  ResultCode code =
+      app_id.empty() ? ResultCode::kInstallationFailed : ResultCode::kSuccess;
+  std::move(result_callback).Run(Result(code, app_id));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.h b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.h
index 1e9902a..88646e9 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_installation_task.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_SHORTCUT_INSTALLATION_TASK_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/callback.h"
@@ -40,7 +41,7 @@
   void OnGetIcons(ResultCallback result_callback,
                   std::unique_ptr<WebApplicationInfo> web_app_info,
                   std::vector<WebApplicationInfo::IconInfo> icons);
-  void OnInstalled(ResultCallback result_callback, bool success);
+  void OnInstalled(ResultCallback result_callback, const std::string& app_id);
 
   base::WeakPtrFactory<BookmarkAppShortcutInstallationTask> weak_ptr_factory_{
       this};
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
index 4bef8222..7fbb915 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -43,7 +44,7 @@
                                         InstallCallback callback) {
   // The app is already being installed.
   if (current_install_info_ && *current_install_info_ == app_to_install) {
-    std::move(callback).Run(false);
+    std::move(callback).Run(std::string());
     return;
   }
 
@@ -82,7 +83,7 @@
   }
 
   if (validated_url != current_install_info_->url) {
-    std::move(current_install_callback_).Run(false);
+    std::move(current_install_callback_).Run(std::string());
     return;
   }
 
@@ -114,7 +115,7 @@
   web_contents_.reset();
   current_install_info_.reset();
 
-  std::move(current_install_callback_).Run(false);
+  std::move(current_install_callback_).Run(std::string());
 }
 
 void PendingBookmarkAppManager::OnInstalled(
@@ -123,8 +124,7 @@
   // queued installation requests.
   web_contents_.reset();
   current_install_info_.reset();
-  std::move(current_install_callback_)
-      .Run(result == BookmarkAppInstallationTask::Result::kSuccess);
+  std::move(current_install_callback_).Run(result.app_id);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
index cf38470..b808e8f 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -39,8 +40,12 @@
       content::WebContents* web_contents,
       BookmarkAppInstallationTask::ResultCallback callback) override {
     std::move(callback).Run(
-        succeeds_ ? BookmarkAppInstallationTask::Result::kSuccess
-                  : BookmarkAppInstallationTask::Result::kInstallationFailed);
+        succeeds_
+            ? BookmarkAppInstallationTask::Result(
+                  BookmarkAppInstallationTask::ResultCode::kSuccess, "12345")
+            : BookmarkAppInstallationTask::Result(
+                  BookmarkAppInstallationTask::ResultCode::kInstallationFailed,
+                  std::string()));
   }
 
  private:
@@ -85,8 +90,8 @@
                                                                      false);
   }
 
-  void InstallCallback(bool succeeded) {
-    install_succeeded_ = succeeded;
+  void InstallCallback(const std::string& app_id) {
+    install_succeeded_ = !app_id.empty();
   }
 
  protected:
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 1db083d..1d8101b 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -51,8 +51,8 @@
     "channel": "trunk",
     "extension_types": ["platform_app"],
     "whitelist": [
-      "D8524F339305807AB2439035774F746F739D0983"  // Test platform app
-      // TODO(crbug.com/819404): Whitelist the Highlights app.
+      "46578A13607D38F1DC8E280C4F499FB0A2F9565C", // http://crbug.com/819404
+      "898FB5A39687D210766B8998BA4530B99C9E6586"  // http://crbug.com/819404
     ]
   },
   "autofillPrivate": {
diff --git a/chrome/common/google_url_loader_throttle.cc b/chrome/common/google_url_loader_throttle.cc
index 6fd22cf..9855d649 100644
--- a/chrome/common/google_url_loader_throttle.cc
+++ b/chrome/common/google_url_loader_throttle.cc
@@ -9,15 +9,15 @@
 
 GoogleURLLoaderThrottle::GoogleURLLoaderThrottle(
     bool is_off_the_record,
-    bool is_signed_in,
     bool force_safe_search,
     int32_t youtube_restrict,
-    const std::string& allowed_domains_for_apps)
+    const std::string& allowed_domains_for_apps,
+    const std::string& variation_ids_header)
     : is_off_the_record_(is_off_the_record),
-      is_signed_in_(is_signed_in),
       force_safe_search_(force_safe_search),
       youtube_restrict_(youtube_restrict),
-      allowed_domains_for_apps_(allowed_domains_for_apps) {}
+      allowed_domains_for_apps_(allowed_domains_for_apps),
+      variation_ids_header_(variation_ids_header) {}
 
 GoogleURLLoaderThrottle::~GoogleURLLoaderThrottle() {}
 
@@ -26,12 +26,12 @@
 void GoogleURLLoaderThrottle::WillStartRequest(
     network::ResourceRequest* request,
     bool* defer) {
-  variations::AppendVariationHeaders(
-      request->url,
-      is_off_the_record_ ? variations::InIncognito::kYes
-                         : variations::InIncognito::kNo,
-      is_signed_in_ ? variations::SignedIn::kYes : variations::SignedIn::kNo,
-      &request->headers);
+  if (!is_off_the_record_ &&
+      variations::ShouldAppendVariationHeaders(request->url) &&
+      !variation_ids_header_.empty()) {
+    request->headers.SetHeaderIfMissing(variations::kClientDataHeader,
+                                        variation_ids_header_);
+  }
 
   if (force_safe_search_) {
     GURL new_url;
@@ -61,9 +61,6 @@
     const network::ResourceResponseHead& response_head,
     bool* defer,
     std::vector<std::string>* to_be_removed_headers) {
-  if (!variations::internal::ShouldAppendVariationHeaders(
-          redirect_info.new_url)) {
-    const char kClientData[] = "X-Client-Data";
-    to_be_removed_headers->push_back(kClientData);
-  }
+  if (!variations::ShouldAppendVariationHeaders(redirect_info.new_url))
+    to_be_removed_headers->push_back(variations::kClientDataHeader);
 }
diff --git a/chrome/common/google_url_loader_throttle.h b/chrome/common/google_url_loader_throttle.h
index 5c9d530..2765148 100644
--- a/chrome/common/google_url_loader_throttle.h
+++ b/chrome/common/google_url_loader_throttle.h
@@ -15,10 +15,10 @@
       public base::SupportsWeakPtr<GoogleURLLoaderThrottle> {
  public:
   GoogleURLLoaderThrottle(bool is_off_the_record,
-                          bool is_signed_in,
                           bool force_safe_search,
                           int32_t youtube_restrict,
-                          const std::string& allowed_domains_for_apps);
+                          const std::string& allowed_domains_for_apps,
+                          const std::string& variation_ids_header);
   ~GoogleURLLoaderThrottle() override;
 
  private:
@@ -33,10 +33,10 @@
       std::vector<std::string>* to_be_removed_headers) override;
 
   bool is_off_the_record_;
-  bool is_signed_in_;
   bool force_safe_search_;
   int32_t youtube_restrict_;
   std::string allowed_domains_for_apps_;
+  std::string variation_ids_header_;
 };
 
 #endif  // CHROME_COMMON_GOOGLE_URL_LOADER_THROTTLE_H_
diff --git a/chrome/common/media_router/providers/cast/cast_media_source.cc b/chrome/common/media_router/providers/cast/cast_media_source.cc
index 8f97a0d..3a978ec3 100644
--- a/chrome/common/media_router/providers/cast/cast_media_source.cc
+++ b/chrome/common/media_router/providers/cast/cast_media_source.cc
@@ -7,7 +7,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
 #include "chrome/common/media_router/media_source_helper.h"
 #include "net/base/url_util.h"
 #include "url/gurl.h"
@@ -70,16 +69,10 @@
 
 std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring(
     const MediaSource::Id& source_id) {
-// Desktop audio mirroring is only supported on some platforms.
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
-  return std::make_unique<CastMediaSource>(
-      source_id,
-      std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId),
-                                CastAppInfo(kCastStreamingAudioAppId)}));
-#else
+  // TODO(https://crbug.com/849335): Add back audio-only devices for desktop
+  // mirroring when proper support is implemented.
   return std::make_unique<CastMediaSource>(
       source_id, std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId)}));
-#endif
 }
 
 std::unique_ptr<CastMediaSource> CreateFromURLParams(
diff --git a/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc b/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
index 54181fdc..5ab5eaa 100644
--- a/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
+++ b/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
@@ -63,8 +63,8 @@
   ASSERT_TRUE(source);
   EXPECT_EQ(source_id, source->source_id());
   ASSERT_EQ(2u, source->app_infos().size());
-  EXPECT_EQ("0F5096E8", source->app_infos()[0].app_id);
-  EXPECT_EQ("85CDB22F", source->app_infos()[1].app_id);
+  EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
+  EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
   EXPECT_TRUE(source->client_id().empty());
   EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
 }
@@ -75,8 +75,19 @@
   ASSERT_TRUE(source);
   EXPECT_EQ(source_id, source->source_id());
   ASSERT_EQ(2u, source->app_infos().size());
-  EXPECT_EQ("0F5096E8", source->app_infos()[0].app_id);
-  EXPECT_EQ("85CDB22F", source->app_infos()[1].app_id);
+  EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
+  EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
+  EXPECT_TRUE(source->client_id().empty());
+  EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
+}
+
+TEST(CastMediaSourceTest, FromDesktopUrn) {
+  MediaSource::Id source_id("urn:x-org.chromium.media:source:desktop");
+  std::unique_ptr<CastMediaSource> source = CastMediaSource::From(source_id);
+  ASSERT_TRUE(source);
+  EXPECT_EQ(source_id, source->source_id());
+  ASSERT_EQ(1u, source->app_infos().size());
+  EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
   EXPECT_TRUE(source->client_id().empty());
   EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
 }
diff --git a/chrome/common/renderer_configuration.mojom b/chrome/common/renderer_configuration.mojom
index f95d1b7..1daffe6 100644
--- a/chrome/common/renderer_configuration.mojom
+++ b/chrome/common/renderer_configuration.mojom
@@ -12,10 +12,10 @@
   SetInitialConfiguration(bool is_incognito_process);
 
   // Update renderer configuration with settings that can change.
-  SetConfiguration(bool is_signed_in,
-                   bool force_safe_search,
+  SetConfiguration(bool force_safe_search,
                    int32 youtube_restrict,
-                   string allowed_domains_for_apps);
+                   string allowed_domains_for_apps,
+                   string variation_ids_header);
 
   // Set the content setting rules stored by the renderer.
   SetContentSettingRules(
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index 1d3f354..8832d25 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -520,75 +520,114 @@
   ExpectAutomaticGenerationAvailable("first_password", true);
 }
 
-TEST_F(PasswordGenerationAgentTest, MaximumOfferSize) {
-  for (size_t maximum_offer_size : {0, 5}) {
-    SCOPED_TRACE(testing::Message()
-                 << "maximum_offer_size = " << maximum_offer_size);
-    password_generation_->set_maximum_offer_size_for_testing(
-        maximum_offer_size);
-    EXPECT_EQ(maximum_offer_size, password_generation_->maximum_offer_size());
+TEST_F(PasswordGenerationAgentTest, MaximumCharsForGenerationOffer) {
+  base::HistogramTester histogram_tester;
 
-    base::HistogramTester histogram_tester;
+  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
+  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
+  SetAccountCreationFormsDetectedMessage(password_generation_,
+                                         GetMainFrame()->GetDocument(), 0, 1);
+  // There should now be a message to show the UI.
+  ExpectAutomaticGenerationAvailable("first_password", true);
 
-    LoadHTMLWithUserGesture(kAccountCreationFormHTML);
-    SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
-    SetAccountCreationFormsDetectedMessage(password_generation_,
-                                           GetMainFrame()->GetDocument(), 0, 1);
-    // There should now be a message to show the UI.
-    ExpectAutomaticGenerationAvailable("first_password", true);
+  WebDocument document = GetMainFrame()->GetDocument();
+  WebElement element =
+      document.GetElementById(WebString::FromUTF8("first_password"));
+  ASSERT_FALSE(element.IsNull());
+  WebInputElement first_password_element = element.To<WebInputElement>();
 
-    WebDocument document = GetMainFrame()->GetDocument();
-    WebElement element =
-        document.GetElementById(WebString::FromUTF8("first_password"));
-    ASSERT_FALSE(element.IsNull());
-    WebInputElement first_password_element = element.To<WebInputElement>();
+  // Make a password just under maximum offer size.
+  SimulateUserInputChangeForElement(
+      &first_password_element,
+      std::string(PasswordGenerationAgent::kMaximumCharsForGenerationOffer,
+                  'a'));
 
-    // Make a password just under maximum offer size.
-    if (password_generation_->maximum_offer_size() > 0) {
-      SimulateUserInputChangeForElement(
-          &first_password_element,
-          std::string(password_generation_->maximum_offer_size(), 'a'));
+  // There should still be a message to show the UI.
+  EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
+  fake_pw_client_.reset_called_automatic_generation_status_changed_true();
+  fake_pw_client_.reset_called_password_generation_rejected_by_typing();
 
-      // There should still be a message to show the UI.
-      EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
-      fake_pw_client_.reset_called_automatic_generation_status_changed_true();
-      fake_pw_client_.reset_called_password_generation_rejected_by_typing();
-    }
+  // Simulate a user typing a password just over maximum offer size.
+  SimulateUserTypingASCIICharacter('a', true);
+  // There should now be a message that generation was rejected.
+  fake_pw_client_.Flush();
+  EXPECT_TRUE(fake_pw_client_.called_password_generation_rejected_by_typing());
+  fake_pw_client_.reset_called_password_generation_rejected_by_typing();
 
-    // Simulate a user typing a password just over maximum offer size.
-    SimulateUserTypingASCIICharacter('a', true);
-    // There should now be a message that generation was rejected.
-    fake_pw_client_.Flush();
-    EXPECT_TRUE(
-        fake_pw_client_.called_password_generation_rejected_by_typing());
-    fake_pw_client_.reset_called_show_manual_pw_generation_popup();
+  // Simulate the user deleting characters. The generation popup should be
+  // shown again.
+  SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
+  // There should now be a message to show the UI.
+  EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
+  fake_pw_client_.reset_called_automatic_generation_status_changed_true();
 
-    // Simulate the user deleting characters. The generation popup should be
-    // shown again.
-    SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
-    // There should now be a message to show the UI.
-    EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
-    fake_pw_client_.reset_called_automatic_generation_status_changed_true();
+  // Change focus. Bubble should be hidden, but that is handled by
+  // AutofilAgent, so no messages are sent.
+  ExecuteJavaScriptForTests("document.getElementById('username').focus();");
+  EXPECT_FALSE(GetCalledAutomaticGenerationStatusChangedTrue());
 
-    // Change focus. Bubble should be hidden, but that is handled by
-    // AutofilAgent, so no messages are sent.
-    ExecuteJavaScriptForTests("document.getElementById('username').focus();");
-    EXPECT_FALSE(GetCalledAutomaticGenerationStatusChangedTrue());
+  // Focusing the password field will bring up the generation UI again.
+  ExecuteJavaScriptForTests(
+      "document.getElementById('first_password').focus();");
+  EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
+  fake_pw_client_.reset_called_automatic_generation_status_changed_true();
 
-    // Focusing the password field will bring up the generation UI again.
-    ExecuteJavaScriptForTests(
-        "document.getElementById('first_password').focus();");
-    EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
-    fake_pw_client_.reset_called_automatic_generation_status_changed_true();
+  // Loading a different page triggers UMA stat upload. Verify that only one
+  // display event is sent.
+  LoadHTMLWithUserGesture(kSigninFormHTML);
 
-    // Loading a different page triggers UMA stat upload. Verify that only one
-    // display event is sent.
-    LoadHTMLWithUserGesture(kSigninFormHTML);
+  histogram_tester.ExpectBucketCount(
+      "PasswordGeneration.Event",
+      autofill::password_generation::GENERATION_POPUP_SHOWN, 1);
+}
 
-    histogram_tester.ExpectBucketCount(
-        "PasswordGeneration.Event",
-        autofill::password_generation::GENERATION_POPUP_SHOWN, 1);
-  }
+TEST_F(PasswordGenerationAgentTest, MinimumLengthForEditedPassword) {
+  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
+  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
+  SetAccountCreationFormsDetectedMessage(password_generation_,
+                                         GetMainFrame()->GetDocument(), 0, 1);
+
+  // Generate a new password.
+  base::string16 password = base::ASCIIToUTF16("random_password");
+  EXPECT_CALL(fake_pw_client_,
+              PresaveGeneratedPassword(testing::Field(
+                  &autofill::PasswordForm::password_value, password)));
+  password_generation_->GeneratedPasswordAccepted(password);
+  fake_pw_client_.Flush();
+  testing::Mock::VerifyAndClearExpectations(&fake_pw_client_);
+
+  // Delete most of the password.
+  FocusField("first_password");
+  size_t max_chars_to_delete =
+      password.length() -
+      PasswordGenerationAgent::kMinimumLengthForEditedPassword;
+  EXPECT_CALL(fake_pw_client_, PresaveGeneratedPassword(testing::_))
+      .Times(testing::AtLeast(1));
+  for (size_t i = 0; i < max_chars_to_delete; ++i)
+    SimulateUserTypingASCIICharacter(ui::VKEY_BACK, false);
+  fake_pw_client_.Flush();
+  testing::Mock::VerifyAndClearExpectations(&fake_pw_client_);
+  EXPECT_FALSE(GetCalledAutomaticGenerationStatusChangedTrue());
+
+  // Delete one more character. The state should move to offering generation.
+  EXPECT_CALL(fake_pw_client_, PasswordNoLongerGenerated(testing::_));
+  SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
+  fake_pw_client_.Flush();
+  testing::Mock::VerifyAndClearExpectations(&fake_pw_client_);
+  EXPECT_TRUE(GetCalledAutomaticGenerationStatusChangedTrue());
+
+  // The first password field is still non empty. The second one should be
+  // cleared.
+  WebDocument document = GetMainFrame()->GetDocument();
+  WebElement element =
+      document.GetElementById(WebString::FromUTF8("first_password"));
+  ASSERT_FALSE(element.IsNull());
+  WebInputElement first_password_element = element.To<WebInputElement>();
+  element = document.GetElementById(WebString::FromUTF8("second_password"));
+  ASSERT_FALSE(element.IsNull());
+  WebInputElement second_password_element = element.To<WebInputElement>();
+  EXPECT_NE(base::string16(), first_password_element.Value().Utf16());
+  EXPECT_EQ(base::string16(), second_password_element.Value().Utf16());
 }
 
 TEST_F(PasswordGenerationAgentTest, DynamicFormTest) {
@@ -876,7 +915,7 @@
   const char* kTextFieldId = "username";
 
   ExpectAutomaticGenerationAvailable(kGenerationElementId, true);
-  base::string16 password = base::ASCIIToUTF16("pwd");
+  base::string16 password = base::ASCIIToUTF16("long_pwd");
   EXPECT_CALL(fake_pw_client_,
               PresaveGeneratedPassword(testing::Field(
                   &autofill::PasswordForm::password_value, password)));
@@ -911,7 +950,7 @@
 
   const char kGenerationElementId[] = "first_password";
   ExpectAutomaticGenerationAvailable(kGenerationElementId, true);
-  base::string16 password = base::ASCIIToUTF16("pwd");
+  base::string16 password = base::ASCIIToUTF16("long_pwd");
   EXPECT_CALL(fake_pw_client_,
               PresaveGeneratedPassword(testing::Field(
                   &autofill::PasswordForm::password_value, password)));
diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
index e5cccd3..a23117de 100644
--- a/chrome/renderer/chrome_render_thread_observer.cc
+++ b/chrome/renderer/chrome_render_thread_observer.cc
@@ -135,10 +135,10 @@
 }  // namespace
 
 bool ChromeRenderThreadObserver::is_incognito_process_ = false;
-bool ChromeRenderThreadObserver::is_signed_in_ = false;
 bool ChromeRenderThreadObserver::force_safe_search_ = false;
 int32_t ChromeRenderThreadObserver::youtube_restrict_ = 0;
 std::string* ChromeRenderThreadObserver::allowed_domains_for_apps_ = nullptr;
+std::string* ChromeRenderThreadObserver::variation_ids_header_ = nullptr;
 
 ChromeRenderThreadObserver::ChromeRenderThreadObserver()
     : visited_link_slave_(new visitedlink::VisitedLinkSlave),
@@ -196,16 +196,18 @@
 }
 
 void ChromeRenderThreadObserver::SetConfiguration(
-    bool is_signed_in,
     bool force_safe_search,
     int32_t youtube_restrict,
-    const std::string& allowed_domains_for_apps) {
-  is_signed_in_ = is_signed_in;
+    const std::string& allowed_domains_for_apps,
+    const std::string& variation_ids_header) {
   force_safe_search_ = force_safe_search;
   youtube_restrict_ = youtube_restrict;
   if (!allowed_domains_for_apps_)
     allowed_domains_for_apps_ = new std::string();
   *allowed_domains_for_apps_ = allowed_domains_for_apps;
+  if (!variation_ids_header_)
+    variation_ids_header_ = new std::string();
+  *variation_ids_header_ = variation_ids_header;
 }
 
 void ChromeRenderThreadObserver::SetContentSettingRules(
diff --git a/chrome/renderer/chrome_render_thread_observer.h b/chrome/renderer/chrome_render_thread_observer.h
index 9af2d57..f999803 100644
--- a/chrome/renderer/chrome_render_thread_observer.h
+++ b/chrome/renderer/chrome_render_thread_observer.h
@@ -35,12 +35,14 @@
   ~ChromeRenderThreadObserver() override;
 
   static bool is_incognito_process() { return is_incognito_process_; }
-  static bool is_signed_in() { return is_signed_in_; }
   static bool force_safe_search() { return force_safe_search_; }
   static int32_t youtube_restrict() { return youtube_restrict_; }
   static const std::string& allowed_domains_for_apps() {
     return *allowed_domains_for_apps_;
   }
+  static const std::string& variation_ids_header() {
+    return *variation_ids_header_;
+  }
 
   // Returns a pointer to the content setting rules owned by
   // |ChromeRenderThreadObserver|.
@@ -59,10 +61,10 @@
 
   // chrome::mojom::RendererConfiguration:
   void SetInitialConfiguration(bool is_incognito_process) override;
-  void SetConfiguration(bool is_signed_in,
-                        bool force_safe_search,
+  void SetConfiguration(bool force_safe_search,
                         int32_t youtube_restrict,
-                        const std::string& allowed_domains_for_apps) override;
+                        const std::string& allowed_domains_for_apps,
+                        const std::string& variation_ids_header) override;
   void SetContentSettingRules(
       const RendererContentSettingRules& rules) override;
   void SetFieldTrialGroup(const std::string& trial_name,
@@ -72,10 +74,10 @@
       chrome::mojom::RendererConfigurationAssociatedRequest request);
 
   static bool is_incognito_process_;
-  static bool is_signed_in_;
   static bool force_safe_search_;
   static int32_t youtube_restrict_;
   static std::string* allowed_domains_for_apps_;
+  static std::string* variation_ids_header_;
   std::unique_ptr<content::ResourceDispatcherDelegate> resource_delegate_;
   RendererContentSettingRules content_setting_rules_;
 
diff --git a/chrome/renderer/url_loader_throttle_provider_impl.cc b/chrome/renderer/url_loader_throttle_provider_impl.cc
index 7874b84e..3c38ef8 100644
--- a/chrome/renderer/url_loader_throttle_provider_impl.cc
+++ b/chrome/renderer/url_loader_throttle_provider_impl.cc
@@ -245,10 +245,10 @@
 
   throttles.push_back(std::make_unique<GoogleURLLoaderThrottle>(
       ChromeRenderThreadObserver::is_incognito_process(),
-      ChromeRenderThreadObserver::is_signed_in(),
       ChromeRenderThreadObserver::force_safe_search(),
       ChromeRenderThreadObserver::youtube_restrict(),
-      ChromeRenderThreadObserver::allowed_domains_for_apps()));
+      ChromeRenderThreadObserver::allowed_domains_for_apps(),
+      ChromeRenderThreadObserver::variation_ids_header()));
 
   return throttles;
 }
diff --git a/chrome/services/isolated_xr_device/BUILD.gn b/chrome/services/isolated_xr_device/BUILD.gn
new file mode 100644
index 0000000..e371a3f
--- /dev/null
+++ b/chrome/services/isolated_xr_device/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+
+source_set("lib") {
+  sources = [
+    "xr_device_service.cc",
+    "xr_device_service.h",
+    "xr_runtime_provider.cc",
+    "xr_runtime_provider.h",
+  ]
+
+  deps = [
+    "//base",
+    "//device/vr:vr",
+    "//device/vr/public/mojom",
+    "//services/service_manager/public/cpp",
+    "//services/service_manager/public/mojom",
+  ]
+}
+
+service_manifest("manifest") {
+  name = "xr_device_service"
+  source = "manifest.json"
+}
diff --git a/chrome/services/isolated_xr_device/DEPS b/chrome/services/isolated_xr_device/DEPS
new file mode 100644
index 0000000..a210e73d
--- /dev/null
+++ b/chrome/services/isolated_xr_device/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+device/vr",
+  "+mojo/public",
+  "+services/service_manager/public"
+]
\ No newline at end of file
diff --git a/chrome/services/isolated_xr_device/OWNERS b/chrome/services/isolated_xr_device/OWNERS
new file mode 100644
index 0000000..b19eacaf
--- /dev/null
+++ b/chrome/services/isolated_xr_device/OWNERS
@@ -0,0 +1,6 @@
+billorr@chromium.org
+mthiesse@chromium.org
+ddorwin@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/isolated_xr_device/manifest.json b/chrome/services/isolated_xr_device/manifest.json
new file mode 100644
index 0000000..5346733
--- /dev/null
+++ b/chrome/services/isolated_xr_device/manifest.json
@@ -0,0 +1,14 @@
+{
+  "name": "xr_device_service",
+  "display_name": "XR Isolated Device Service",
+  "sandbox_type": "none",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "xr_device_provider": [ "device.mojom.IsolatedXRRuntimeProvider" ]
+      },
+      "requires": {
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/chrome/services/isolated_xr_device/xr_device_service.cc b/chrome/services/isolated_xr_device/xr_device_service.cc
new file mode 100644
index 0000000..45e9138
--- /dev/null
+++ b/chrome/services/isolated_xr_device/xr_device_service.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/services/isolated_xr_device/xr_device_service.h"
+
+#include "base/bind.h"
+#include "chrome/services/isolated_xr_device/xr_runtime_provider.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/service_manager/public/cpp/service_context.h"
+
+namespace device {
+
+std::unique_ptr<service_manager::Service>
+XrDeviceService::CreateXrDeviceService() {
+  return std::make_unique<XrDeviceService>();
+}
+
+void XrDeviceService::OnDeviceProviderRequest(
+    device::mojom::IsolatedXRRuntimeProviderRequest request) {
+  mojo::MakeStrongBinding(
+      std::make_unique<IsolatedXRRuntimeProvider>(ref_factory_->CreateRef()),
+      std::move(request));
+}
+
+XrDeviceService::XrDeviceService() {
+  // Register device provider here.
+  registry_.AddInterface(base::BindRepeating(
+      &XrDeviceService::OnDeviceProviderRequest, base::Unretained(this)));
+}
+
+XrDeviceService::~XrDeviceService() {}
+
+void XrDeviceService::OnStart() {
+  ref_factory_ = std::make_unique<service_manager::ServiceContextRefFactory>(
+      context()->CreateQuitClosure());
+}
+
+void XrDeviceService::OnBindInterface(
+    const service_manager::BindSourceInfo& source_info,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  registry_.BindInterface(interface_name, std::move(interface_pipe));
+}
+
+}  // namespace device
diff --git a/chrome/services/isolated_xr_device/xr_device_service.h b/chrome/services/isolated_xr_device/xr_device_service.h
new file mode 100644
index 0000000..fe8cb8ab
--- /dev/null
+++ b/chrome/services/isolated_xr_device/xr_device_service.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_DEVICE_SERVICE_H_
+#define CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_DEVICE_SERVICE_H_
+
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.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_context.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace device {
+
+class XrDeviceService : public service_manager::Service {
+ public:
+  static std::unique_ptr<service_manager::Service> CreateXrDeviceService();
+
+  XrDeviceService();
+  ~XrDeviceService() override;
+  void OnDeviceProviderRequest(
+      device::mojom::IsolatedXRRuntimeProviderRequest request);
+
+ 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;
+
+  service_manager::BinderRegistry registry_;
+
+  std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(XrDeviceService);
+};
+
+}  // namespace device
+
+#endif  // CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_DEVICE_SERVICE_H_
diff --git a/chrome/services/isolated_xr_device/xr_runtime_provider.cc b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
new file mode 100644
index 0000000..0298898e
--- /dev/null
+++ b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/services/isolated_xr_device/xr_runtime_provider.h"
+#include "chrome/common/chrome_features.h"
+#include "device/vr/buildflags/buildflags.h"
+
+#if BUILDFLAG(ENABLE_OPENVR)
+#include "device/vr/openvr/openvr_device.h"
+#endif
+
+#if BUILDFLAG(ENABLE_OCULUS_VR)
+#include "device/vr/oculus/oculus_device.h"
+#endif
+
+void IsolatedXRRuntimeProvider::RequestDevices(
+    device::mojom::IsolatedXRRuntimeProviderClientPtr client) {
+#if BUILDFLAG(ENABLE_OCULUS_VR)
+  if (base::FeatureList::IsEnabled(features::kOculusVR)) {
+    oculus_device_ = std::make_unique<device::OculusDevice>();
+    if (!oculus_device_->IsInitialized()) {
+      oculus_device_ = nullptr;
+    } else {
+      client->OnDeviceAdded(oculus_device_->BindXRRuntimePtr(),
+                            oculus_device_->BindGamepadFactory(),
+                            oculus_device_->GetVRDisplayInfo());
+    }
+  }
+#endif
+
+#if BUILDFLAG(ENABLE_OPENVR)
+  if (base::FeatureList::IsEnabled(features::kOpenVR)) {
+    openvr_device_ = std::make_unique<device::OpenVRDevice>();
+    if (!openvr_device_->IsInitialized()) {
+      openvr_device_ = nullptr;
+    } else {
+      client->OnDeviceAdded(openvr_device_->BindXRRuntimePtr(),
+                            openvr_device_->BindGamepadFactory(),
+                            openvr_device_->GetVRDisplayInfo());
+    }
+  }
+#endif
+
+  client->OnDevicesEnumerated();
+  client_ = std::move(client);
+}
+
+IsolatedXRRuntimeProvider::IsolatedXRRuntimeProvider(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+    : service_ref_(std::move(service_ref)) {}
+
+IsolatedXRRuntimeProvider::~IsolatedXRRuntimeProvider() {}
diff --git a/chrome/services/isolated_xr_device/xr_runtime_provider.h b/chrome/services/isolated_xr_device/xr_runtime_provider.h
new file mode 100644
index 0000000..a68f3bd
--- /dev/null
+++ b/chrome/services/isolated_xr_device/xr_runtime_provider.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_RUNTIME_PROVIDER_H_
+#define CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_RUNTIME_PROVIDER_H_
+
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace device {
+class OculusDevice;
+class OpenVRDevice;
+}  // namespace device
+
+class IsolatedXRRuntimeProvider
+    : public device::mojom::IsolatedXRRuntimeProvider {
+ public:
+  IsolatedXRRuntimeProvider(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  ~IsolatedXRRuntimeProvider() final;
+
+  void RequestDevices(
+      device::mojom::IsolatedXRRuntimeProviderClientPtr client) override;
+
+ private:
+  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+
+  IsolatedXRRuntimeProvider();
+
+  std::unique_ptr<device::OculusDevice> oculus_device_;
+  std::unique_ptr<device::OpenVRDevice> openvr_device_;
+
+  device::mojom::IsolatedXRRuntimeProviderClientPtr client_;
+};
+
+#endif  // CHROME_SERVICES_ISOLATED_XR_DEVICE_XR_RUNTIME_PROVIDER_H_
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 95a5226..34ab935 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -205,10 +205,6 @@
       "base/test_browser_window.cc",
       "base/test_browser_window.h",
     ]
-    if (enable_vr) {
-      # Add a dummy implementation of RegisterJni to satisfy the linker.
-      sources += [ "../browser/android/vr/register_jni_monochrome.cc" ]
-    }
   } else {
     public_deps += [
       "//components/ukm:test_support",
@@ -1091,7 +1087,7 @@
       "//third_party/mocha/mocha.js",
       "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/simplejson/",
       "//third_party/tlslite/",
       "//ui/webui/resources/js/",
@@ -1840,6 +1836,7 @@
         "//ui/login:resources",
         "//url",
       ]
+      data_deps += [ "//ui/file_manager:unit_test_data" ]
       if (use_dbus) {
         deps += [ "//dbus:test_support" ]
       }
@@ -2818,7 +2815,7 @@
     "//third_party/accessibility-audit/axs_testing.js",
     "//third_party/chaijs/chai.js",
     "//third_party/pyftpdlib/",
-    "//third_party/pywebsocket/",
+    "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
     "//third_party/zlib/google/test/data/",
     "//tools/metrics/histograms/enums.xml",
@@ -4837,7 +4834,7 @@
       "//third_party/mocha/mocha.js",
       "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
       "//third_party/zlib/google/test/data/",
       "//tools/metrics/histograms/enums.xml",
@@ -5499,9 +5496,8 @@
       "//net/tools/testserver/",
       "//components/sync/tools/testserver/",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
-      "$root_out_dir/pyproto/",
       "//testing/xvfb.py",
     ]
 
@@ -5530,6 +5526,7 @@
       "//chrome/common",
       "//chrome/renderer",
       "//components/sync",
+      "//components/sync/protocol:chromiumsync_pyproto",
       "//crypto:platform",
       "//testing/gmock",
       "//testing/gtest",
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index b4e8d51..df8efa88 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -26,12 +26,13 @@
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/prefs/pref_service.h"
 #include "components/subresource_filter/content/browser/content_ruleset_service.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/buildflags/buildflags.h"
 #include "media/media_buildflags.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "printing/buildflags/buildflags.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
@@ -57,25 +58,6 @@
 #include "components/keep_alive_registry/keep_alive_registry.h"
 #endif
 
-namespace {
-
-class MockNetworkConnectionTracker : public network::NetworkConnectionTracker {
- public:
-  MockNetworkConnectionTracker() : network::NetworkConnectionTracker() {}
-  ~MockNetworkConnectionTracker() override {}
-
-  bool GetConnectionType(network::mojom::ConnectionType* type,
-                         ConnectionTypeCallback callback) override {
-    *type = network::mojom::ConnectionType::CONNECTION_UNKNOWN;
-    return true;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockNetworkConnectionTracker);
-};
-
-}  // namespace
-
 // static
 TestingBrowserProcess* TestingBrowserProcess::GetGlobal() {
   return static_cast<TestingBrowserProcess*>(g_browser_process);
@@ -103,7 +85,14 @@
       io_thread_(nullptr),
       system_request_context_(nullptr),
       rappor_service_(nullptr),
-      platform_part_(new TestingBrowserProcessPlatformPart()) {
+      platform_part_(new TestingBrowserProcessPlatformPart()),
+      test_network_connection_tracker_(
+          new network::TestNetworkConnectionTracker(
+              true /* respond_synchronously */,
+              network::mojom::ConnectionType::CONNECTION_UNKNOWN)) {
+  content::SetNetworkConnectionTrackerForTesting(
+      test_network_connection_tracker_.get());
+
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   extensions_browser_client_.reset(
       new extensions::ChromeExtensionsBrowserClient);
@@ -131,6 +120,8 @@
   tab_manager_.reset();
 #endif
 
+  content::SetNetworkConnectionTrackerForTesting(nullptr);
+
   // Destructors for some objects owned by TestingBrowserProcess will use
   // g_browser_process if it is not null, so it must be null before proceeding.
   DCHECK_EQ(static_cast<BrowserProcess*>(nullptr), g_browser_process);
@@ -176,15 +167,6 @@
   return shared_url_loader_factory_;
 }
 
-network::NetworkConnectionTracker*
-TestingBrowserProcess::network_connection_tracker() {
-  if (!network_connection_tracker_) {
-    network_connection_tracker_ =
-        std::make_unique<MockNetworkConnectionTracker>();
-  }
-  return network_connection_tracker_.get();
-}
-
 network::NetworkQualityTracker*
 TestingBrowserProcess::network_quality_tracker() {
   return nullptr;
@@ -470,11 +452,6 @@
   shared_url_loader_factory_ = shared_url_loader_factory;
 }
 
-void TestingBrowserProcess::SetNetworkConnectionTracker(
-    std::unique_ptr<network::NetworkConnectionTracker> tracker) {
-  network_connection_tracker_ = std::move(tracker);
-}
-
 void TestingBrowserProcess::SetNotificationUIManager(
     std::unique_ptr<NotificationUIManager> notification_ui_manager) {
   notification_ui_manager_.swap(notification_ui_manager);
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index c79a43e3..b0e50a8 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -43,6 +43,10 @@
 class GCMDriver;
 }
 
+namespace network {
+class TestNetworkConnectionTracker;
+}
+
 namespace policy {
 class PolicyService;
 }
@@ -74,7 +78,6 @@
   SystemNetworkContextManager* system_network_context_manager() override;
   scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory()
       override;
-  network::NetworkConnectionTracker* network_connection_tracker() override;
   network::NetworkQualityTracker* network_quality_tracker() override;
   WatchDogThread* watchdog_thread() override;
   ProfileManager* profile_manager() override;
@@ -149,8 +152,6 @@
   void SetSystemRequestContext(net::URLRequestContextGetter* context_getter);
   void SetSharedURLLoaderFactory(
       scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory);
-  void SetNetworkConnectionTracker(
-      std::unique_ptr<network::NetworkConnectionTracker> tracker);
   void SetNotificationUIManager(
       std::unique_ptr<NotificationUIManager> notification_ui_manager);
   void SetNotificationPlatformBridge(
@@ -171,8 +172,6 @@
   std::unique_ptr<policy::ChromeBrowserPolicyConnector>
       browser_policy_connector_;
   bool created_browser_policy_connector_ = false;
-  std::unique_ptr<network::NetworkConnectionTracker>
-      network_connection_tracker_;
   std::unique_ptr<ProfileManager> profile_manager_;
   std::unique_ptr<NotificationUIManager> notification_ui_manager_;
   std::unique_ptr<NotificationPlatformBridge> notification_platform_bridge_;
@@ -212,6 +211,8 @@
   rappor::RapporServiceImpl* rappor_service_;
 
   std::unique_ptr<BrowserProcessPlatformPart> platform_part_;
+  std::unique_ptr<network::TestNetworkConnectionTracker>
+      test_network_connection_tracker_;
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   std::unique_ptr<MediaFileSystemRegistry> media_file_system_registry_;
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index 4fbbc67..7fa5ead13d 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -356,9 +356,8 @@
     return self.ExecuteCommand(
         Command.FIND_ELEMENTS, {'using': strategy, 'value': target})
 
-  def SetTimeout(self, type, timeout):
-    return self.ExecuteCommand(
-        Command.SET_TIMEOUT, {'type' : type, 'ms': timeout})
+  def SetTimeouts(self, params):
+    return self.ExecuteCommand(Command.SET_TIMEOUTS, params)
 
   def GetCurrentUrl(self):
     return self.ExecuteCommand(Command.GET_CURRENT_URL)
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py
index f7ed3c1..ac1d0a9d 100644
--- a/chrome/test/chromedriver/client/command_executor.py
+++ b/chrome/test/chromedriver/client/command_executor.py
@@ -101,7 +101,7 @@
       _Method.POST, '/session/:sessionId/timeouts/implicit_wait')
   SET_SCRIPT_TIMEOUT = (
       _Method.POST, '/session/:sessionId/timeouts/async_script')
-  SET_TIMEOUT = (_Method.POST, '/session/:sessionId/timeouts')
+  SET_TIMEOUTS = (_Method.POST, '/session/:sessionId/timeouts')
   GET_TIMEOUTS = (_Method.GET, '/session/:sessionId/timeouts')
   EXECUTE_SQL = (_Method.POST, '/session/:sessionId/execute_sql')
   GET_LOCATION = (_Method.GET, '/session/:sessionId/location')
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 9593115..0332454 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -100,7 +100,7 @@
           WrapToCommand("GetTimeouts", base::Bind(&ExecuteGetTimeouts))),
       CommandMapping(
           kPost, "session/:sessionId/timeouts",
-          WrapToCommand("SetTimeout", base::Bind(&ExecuteSetTimeout))),
+          WrapToCommand("SetTimeouts", base::Bind(&ExecuteSetTimeouts))),
       CommandMapping(kPost, "session/:sessionId/url",
                      WrapToCommand("Navigate", base::Bind(&ExecuteGet))),
       CommandMapping(
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 357517e..06858a6 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -542,9 +542,11 @@
   return Status(kOk);
 }
 
-Status ExecuteSetTimeout(Session* session,
-                         const base::DictionaryValue& params,
-                         std::unique_ptr<base::Value>* value) {
+// Handles legacy format SetTimeout command.
+// TODO(johnchen@chromium.org): Remove when we stop supporting legacy protocol.
+Status ExecuteSetTimeoutLegacy(Session* session,
+                               const base::DictionaryValue& params,
+                               std::unique_ptr<base::Value>* value) {
   double ms_double;
   if (!params.GetDouble("ms", &ms_double))
     return Status(kUnknownError, "'ms' must be a double");
@@ -554,8 +556,6 @@
 
   base::TimeDelta timeout =
       base::TimeDelta::FromMilliseconds(static_cast<int>(ms_double));
-  // TODO(frankf): implicit and script timeout should be cleared
-  // if negative timeout is specified.
   if (type == "implicit") {
     session->implicit_wait = timeout;
   } else if (type == "script") {
@@ -570,6 +570,41 @@
   return Status(kOk);
 }
 
+Status ExecuteSetTimeoutsW3C(Session* session,
+                             const base::DictionaryValue& params,
+                             std::unique_ptr<base::Value>* value) {
+  for (const auto& setting : params.DictItems()) {
+    int timeout_ms;
+    if (!setting.second.GetAsInteger(&timeout_ms) || timeout_ms < 0)
+      return Status(kInvalidArgument, "value must be a non-negative integer");
+    base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(timeout_ms);
+    const std::string& type = setting.first;
+    if (type == "script") {
+      session->script_timeout = timeout;
+    } else if (type == "pageLoad") {
+      session->page_load_timeout = timeout;
+    } else if (type == "implicit") {
+      session->implicit_wait = timeout;
+    } else {
+      return Status(kInvalidArgument, "unknown type of timeout: " + type);
+    }
+  }
+  return Status(kOk);
+}
+
+Status ExecuteSetTimeouts(Session* session,
+                          const base::DictionaryValue& params,
+                          std::unique_ptr<base::Value>* value) {
+  // TODO(johnchen@chromium.org): Remove legacy version support when we stop
+  // supporting non-W3C protocol. At that time, we can delete the legacy
+  // function and merge the W3C function into this function.
+  if (params.HasKey("ms")) {
+    return ExecuteSetTimeoutLegacy(session, params, value);
+  } else {
+    return ExecuteSetTimeoutsW3C(session, params, value);
+  }
+}
+
 Status ExecuteGetTimeouts(Session* session,
                           const base::DictionaryValue& params,
                           std::unique_ptr<base::Value>* value) {
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h
index 5a57c63..550d42e 100644
--- a/chrome/test/chromedriver/session_commands.h
+++ b/chrome/test/chromedriver/session_commands.h
@@ -80,9 +80,9 @@
 
 // Configure the amount of time that a particular type of operation can execute
 // for before they are aborted and a timeout error is returned to the client.
-Status ExecuteSetTimeout(Session* session,
-                         const base::DictionaryValue& params,
-                         std::unique_ptr<base::Value>* value);
+Status ExecuteSetTimeouts(Session* session,
+                          const base::DictionaryValue& params,
+                          std::unique_ptr<base::Value>* value);
 
 // Get the implicit, script and page load timeouts in milliseconds.
 Status ExecuteGetTimeouts(Session* session,
diff --git a/chrome/test/chromedriver/session_commands_unittest.cc b/chrome/test/chromedriver/session_commands_unittest.cc
index 313d582..94351d7 100644
--- a/chrome/test/chromedriver/session_commands_unittest.cc
+++ b/chrome/test/chromedriver/session_commands_unittest.cc
@@ -41,6 +41,41 @@
   ASSERT_EQ(implicit, 0);
 }
 
+TEST(SessionCommandsTest, ExecuteSetTimeouts) {
+  Session session("id");
+  base::DictionaryValue params;
+  std::unique_ptr<base::Value> value;
+
+  // W3C spec doesn't forbid passing in an empty object, so we should get kOk.
+  Status status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kOk, status.code());
+
+  params.SetInteger("pageLoad", 5000);
+  status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kOk, status.code());
+
+  params.SetInteger("script", 5000);
+  params.SetInteger("implicit", 5000);
+  status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kOk, status.code());
+
+  params.SetInteger("implicit", -5000);
+  status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kInvalidArgument, status.code());
+
+  params.Clear();
+  params.SetInteger("unknown", 5000);
+  status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kInvalidArgument, status.code());
+
+  // Old pre-W3C format.
+  params.Clear();
+  params.SetDouble("ms", 5000.0);
+  params.SetString("type", "page load");
+  status = ExecuteSetTimeouts(&session, params, &value);
+  ASSERT_EQ(kOk, status.code());
+}
+
 TEST(SessionCommandsTest, MergeCapabilities) {
   base::DictionaryValue primary;
   primary.SetString("strawberry", "velociraptor");
diff --git a/chrome/test/chromedriver/test/run_java_tests.py b/chrome/test/chromedriver/test/run_java_tests.py
index 778a8d9..04a0ee73 100755
--- a/chrome/test/chromedriver/test/run_java_tests.py
+++ b/chrome/test/chromedriver/test/run_java_tests.py
@@ -133,19 +133,13 @@
     jvm_args += ['-agentlib:jdwp=transport=%s,server=y,suspend=y,'
                  'address=33081' % transport]
 
-  return _RunAntTest(java_tests_src_dir, test_filter, chromedriver_path,
-                     chrome_path, log_path, android_package_key,
-                     jvm_args, verbose, debug, sys_props)
+  return _RunAntTest(java_tests_src_dir, jvm_args, verbose, sys_props)
 
-def _RunAntTest(java_tests_src_dir, test_filter, chromedriver_path,
-                    chrome_path, log_path, android_package_key,
-                    jvm_args, verbose, debug, sys_props):
+def _RunAntTest(java_tests_src_dir, jvm_args, verbose, sys_props):
   """Runs a single Ant JUnit test suite and returns the |TestResult|s.
 
   Args:
-    test_dir: the directory to run the tests in.
-    test_class: the name of the JUnit test suite class to run.
-    class_path: the Java class path used when running the tests, colon delimited
+    java_tests_src_dir: the directory to run the tests in.
     sys_props: Java system properties to set when running the tests.
     jvm_args: Java VM command line args to use.
     verbose: whether the output should be verbose.
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 96be822..7812cc1c 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -485,7 +485,7 @@
                       self._driver.ExecuteScript, '{{{')
 
   def testExecuteAsyncScript(self):
-    self._driver.SetTimeout('script', 3000)
+    self._driver.SetTimeouts({'script': 3000})
     self.assertRaises(
         chromedriver.ScriptTimeout,
         self._driver.ExecuteAsyncScript,
@@ -1699,7 +1699,7 @@
       # This test is unreliable on Windows, as FindElement can be called too
       # soon, before the child frame is fully loaded. This causes element not
       # found error. Add an implicit wait works around this issue.
-      self._driver.SetTimeout('implicit', 2000)
+      self._driver.SetTimeouts({'implicit': 2000})
     self._driver.Load(self.GetHttpUrlForFile(
         '/chromedriver/cross_domain_iframe.html'))
     a_outer = self._driver.FindElement('tag name', 'a')
@@ -1741,7 +1741,7 @@
     # about 0.1 second on Linux and Windows, but takes half a second or longer
     # on Mac. So we use longer timeout on Mac, 0.5 second on others.
     timeout = 3000 if util.GetPlatformName() == 'mac' else 500
-    self._driver.SetTimeout('page load', timeout)
+    self._driver.SetTimeouts({'pageLoad': timeout})
 
   def tearDown(self):
     super(ChromeDriverPageLoadTimeoutTest, self).tearDown()
diff --git a/chrome/test/data/media/picture-in-picture/player_preload_none.html b/chrome/test/data/media/picture-in-picture/player_preload_none.html
new file mode 100644
index 0000000..55c4002
--- /dev/null
+++ b/chrome/test/data/media/picture-in-picture/player_preload_none.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<video preload=none poster='../../banners/image-512px.png'>
+  <source src='../bigbuck.webm' type='video/webm'>
+</video>
+<script>
+  const video = document.querySelector('video');
+
+  function play() {
+    video.play().then(() => {
+      window.domAutomationController.send(true);
+    });
+  }
+
+  function enterPictureInPicture() {
+    video.requestPictureInPicture().then(() => {
+      window.domAutomationController.send(true);
+    });
+  }
+
+  function changeSrcAndLoad() {
+    video.addEventListener('loadedmetadata', () => {
+      window.domAutomationController.send(true);
+    }, { once: true });
+
+    document.querySelector('source').src = '../bear-640x360-av-enc_av.webm';
+    video.load();
+  }
+
+  function isInPictureInPicture() {
+    window.domAutomationController.send(document.pictureInPictureElement == video);
+  }
+</script>
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 06e274ce..5ce9be6 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1960,6 +1960,29 @@
 });
 
 /**
+ * Test fixture for the multidevice settings subpage.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsMultideviceSubpageTest() {}
+
+CrSettingsMultideviceSubpageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/multidevice_page/multidevice_subpage.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'multidevice_subpage_tests.js',
+  ]),
+};
+
+TEST_F('CrSettingsMultideviceSubpageTest', 'All', function() {
+  mocha.run();
+});
+
+/**
  * Test fixture for the Linux for Chromebook (Crostini) page.
  * @constructor
  * @extends {CrSettingsBrowserTest}
diff --git a/chrome/test/data/webui/settings/multidevice_subpage_tests.js b/chrome/test/data/webui/settings/multidevice_subpage_tests.js
new file mode 100644
index 0000000..31ef914
--- /dev/null
+++ b/chrome/test/data/webui/settings/multidevice_subpage_tests.js
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+suite('Multidevice', function() {
+  let multideviceSubpage = null;
+  // Although HOST_SET_MODES is effectively a constant, it cannot reference the
+  // enum settings.MultiDeviceSettingsMode from here so its initialization is
+  // deferred to the suiteSetup function.
+  let HOST_SET_MODES;
+  const HOST_DEVICE = {
+    name: 'Pixel XL',
+  };
+
+  function setPageContentData(newMode) {
+    multideviceSubpage.pageContentData = {
+      mode: newMode,
+      hostDevice: HOST_DEVICE,
+    };
+    Polymer.dom.flush();
+  }
+
+  suiteSetup(function() {
+    HOST_SET_MODES = [
+      settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER,
+      settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION,
+      settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED,
+    ];
+  });
+
+  setup(function() {
+    multideviceSubpage = document.createElement('settings-multidevice-subpage');
+
+    setPageContentData(settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED);
+    multideviceSubpage.prefs = {
+      multidevice: {sms_connect_enabled: {value: true}},
+      multidevice_setup: {suite_enabled: {value: true}},
+    };
+
+    document.body.appendChild(multideviceSubpage);
+    Polymer.dom.flush();
+  });
+
+  teardown(function() {
+    multideviceSubpage.remove();
+  });
+
+  test('individual features appear only if host is verified', function() {
+    for (const mode of HOST_SET_MODES) {
+      setPageContentData(mode);
+      assertEquals(
+          !!multideviceSubpage.$$('settings-multidevice-feature-item'),
+          mode == settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED);
+    }
+  });
+
+  test('clicking EasyUnlock item routes to screen lock page', function() {
+    multideviceSubpage.$$('#smart-lock-item').$.card.click();
+    assertEquals(settings.getCurrentRoute(), settings.routes.LOCK_SCREEN);
+  });
+
+  test('AndroidMessages item shows correct input control', function() {
+    const inputControl = multideviceSubpage.$$('[slot=feature-controller]');
+
+    multideviceSubpage.androidMessagesRequiresSetup_ = true;
+    Polymer.dom.flush();
+    assertTrue(!!inputControl.querySelector('paper-button'));
+    assertFalse(
+        !!inputControl.querySelector('settings-multidevice-feature-toggle'));
+
+    multideviceSubpage.androidMessagesRequiresSetup_ = false;
+    Polymer.dom.flush();
+    assertFalse(!!inputControl.querySelector('paper-button'));
+    assertTrue(
+        !!inputControl.querySelector('settings-multidevice-feature-toggle'));
+  });
+});
diff --git a/chrome/test/data/workers/fetch_from_service_worker.html b/chrome/test/data/workers/fetch_from_service_worker.html
new file mode 100644
index 0000000..4dbb1d8
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_service_worker.html
@@ -0,0 +1,32 @@
+<script>
+let registration = null;
+
+self.onload = async () => {
+  registration = await navigator.serviceWorker.register(
+      'fetch_from_service_worker.js');
+  if (!registration) {
+    document.body.innerText = 'Registration failed';
+    document.title = 'DONE';
+    return;
+  }
+  registration = await navigator.serviceWorker.ready;
+  document.body.innerText = 'ready';
+  document.title = 'DONE';
+}
+
+function fetch_from_service_worker(url) {
+  document.title = 'Fetching';
+  document.innerText = '';
+  if (!registration) {
+    document.innerText = 'Registration failed';
+    document.title = 'DONE';
+    return;
+  }
+  const channel = new MessageChannel();
+  channel.port1.onmessage = e => {
+    document.body.innerText = e.data;
+    document.title = 'DONE';
+  };
+  registration.active.postMessage({url: url}, [channel.port2]);
+}
+</script>
diff --git a/chrome/test/data/workers/fetch_from_service_worker.js b/chrome/test/data/workers/fetch_from_service_worker.js
new file mode 100644
index 0000000..eb789b3
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_service_worker.js
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+async function MessageHandler(e) {
+  const port = e.ports[0];
+  const response = await fetch(e.data.url);
+  if (!response.ok) {
+    port.postMessage('bad response');
+    return;
+  }
+  const text = await response.text();
+  port.postMessage(text);
+}
+
+self.addEventListener('message', e => {
+  e.waitUntil(MessageHandler(e));
+});
diff --git a/chrome/test/data/workers/fetch_from_shared_worker.html b/chrome/test/data/workers/fetch_from_shared_worker.html
new file mode 100644
index 0000000..c7786eb2
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_shared_worker.html
@@ -0,0 +1,14 @@
+<script>
+const worker = new SharedWorker('fetch_from_shared_worker.js');
+worker.port.onmessage = e => {
+  document.body.innerText += e.data;
+  document.title = 'DONE';
+};
+worker.port.start();
+
+function fetch_from_shared_worker(url) {
+  document.title = 'Fetching';
+  document.body.innerText = '';
+  worker.port.postMessage({url: url});
+}
+</script>
diff --git a/chrome/test/data/workers/fetch_from_shared_worker.js b/chrome/test/data/workers/fetch_from_shared_worker.js
new file mode 100644
index 0000000..1aa389e3
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_shared_worker.js
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+self.onconnect = e => {
+  const port = e.ports[0];
+  port.onmessage = async e => {
+    const response = await fetch(e.data.url);
+    if (!response.ok) {
+      port.postMessage(`Bad response: ${responses.statusText}`);
+      return;
+    }
+    const text = await response.text();
+    port.postMessage(text);
+  }
+};
diff --git a/chrome/test/data/workers/fetch_from_worker.html b/chrome/test/data/workers/fetch_from_worker.html
new file mode 100644
index 0000000..661d2d1
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_worker.html
@@ -0,0 +1,13 @@
+<script>
+const worker = new Worker('fetch_from_worker.js');
+worker.onmessage = e => {
+  document.body.innerText += e.data;
+  document.title = 'DONE';
+};
+
+function fetch_from_worker(url) {
+  document.title = 'Fetching';
+  document.body.innerText = '';
+  worker.postMessage({url: url});
+}
+</script>
diff --git a/chrome/test/data/workers/fetch_from_worker.js b/chrome/test/data/workers/fetch_from_worker.js
new file mode 100644
index 0000000..998025f3
--- /dev/null
+++ b/chrome/test/data/workers/fetch_from_worker.js
@@ -0,0 +1,13 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+self.onmessage = async e => {
+  const response = await fetch(e.data.url);
+  if (!response.ok) {
+    self.postMessage('bad response');
+    return;
+  }
+  const text = await response.text();
+  self.postMessage(text);
+};
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index 20b78f06..8ce1785 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -6,6 +6,7 @@
 import("//build/config/features.gni")
 import("//build/config/sysroot.gni")
 import("//chrome/common/features.gni")
+import("//device/vr/buildflags/buildflags.gni")
 import("//extensions/buildflags/buildflags.gni")
 import("//printing/buildflags/buildflags.gni")
 import("//services/service_manager/public/service_manifest.gni")
@@ -38,6 +39,7 @@
     "//content/public/child",
     "//content/public/common",
     "//content/public/utility",
+    "//device/vr/buildflags",
     "//extensions/buildflags",
     "//ipc",
     "//media",
@@ -204,6 +206,13 @@
     deps += [ "//chrome/services/media_gallery_util:lib" ]
   }
 
+  if (enable_isolated_xr_service) {
+    deps += [
+      "//chrome/services/isolated_xr_device:lib",
+      "//device/vr/public/mojom",
+    ]
+  }
+
   if (enable_simple_browser_service) {
     deps += [
       "//services/content/simple_browser",
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index 92d397d..7ce7d8d 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -5,6 +5,7 @@
   "+chrome/services/cups_ipp_validator/public/mojom",
   "+chrome/services/file_util/file_util_service.h",
   "+chrome/services/file_util/public/mojom",
+  "+chrome/services/isolated_xr_device",
   "+chrome/services/media_gallery_util/media_gallery_util_service.h",
   "+chrome/services/media_gallery_util/public/mojom",
   # TODO(crbug.com/798782): remove dependency to pdf_to_emf_converter_factory.h
@@ -29,6 +30,8 @@
   "+components/wifi",
   "+content/public/child",
   "+content/public/utility",
+  "+device/vr/buildflags",
+  "+device/vr/public",
   "+extensions/common",
   "+extensions/buildflags",
   "+media",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index b97904e3..6a7b621 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -22,6 +22,7 @@
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/simple_connection_filter.h"
 #include "content/public/utility/utility_thread.h"
+#include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/service_manager/embedder/embedded_service_info.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -43,6 +44,10 @@
 #include "chrome/services/util_win/util_win_service.h"
 #endif
 
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+#include "chrome/services/isolated_xr_device/xr_device_service.h"
+#endif
+
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/services/removable_storage_writer/public/mojom/constants.mojom.h"
 #include "chrome/services/removable_storage_writer/removable_storage_writer_service.h"
@@ -185,6 +190,13 @@
     return;
   }
 
+#if BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+  service_manager::EmbeddedServiceInfo service_info;
+  service_info.factory =
+      base::BindRepeating(&device::XrDeviceService::CreateXrDeviceService);
+  services->emplace(device::mojom::kVrIsolatedServiceName, service_info);
+#endif
+
 #if BUILDFLAG(ENABLE_PRINTING)
   service_manager::EmbeddedServiceInfo pdf_compositor_info;
   pdf_compositor_info.factory = base::BindRepeating(
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 9457f12..8b574e9f 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -64,6 +64,7 @@
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "media/base/media.h"
 #include "media/base/media_switches.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/gl/gl_switches.h"
@@ -508,7 +509,7 @@
           cast_browser_process_->pref_service(),
           content::BrowserContext::GetDefaultStoragePartition(
               cast_browser_process_->browser_context())
-              ->GetURLRequestContext()));
+              ->GetURLLoaderFactoryForBrowserProcess()));
   cast_browser_process_->SetRemoteDebuggingServer(
       std::make_unique<RemoteDebuggingServer>(
           cast_browser_process_->browser_client()
diff --git a/chromecast/browser/cast_permission_manager.cc b/chromecast/browser/cast_permission_manager.cc
index bb878a2d..3e61650 100644
--- a/chromecast/browser/cast_permission_manager.cc
+++ b/chromecast/browser/cast_permission_manager.cc
@@ -65,8 +65,8 @@
 
 int CastPermissionManager::SubscribePermissionStatusChange(
     content::PermissionType permission,
+    content::RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   return content::PermissionController::kNoPendingOperation;
 }
diff --git a/chromecast/browser/cast_permission_manager.h b/chromecast/browser/cast_permission_manager.h
index 82809fc..585f998 100644
--- a/chromecast/browser/cast_permission_manager.h
+++ b/chromecast/browser/cast_permission_manager.h
@@ -46,8 +46,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index a27d880f..b58217a 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -36,6 +36,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/histogram_fetcher.h"
 #include "content/public/common/content_switches.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if defined(OS_LINUX)
 #include "chromecast/browser/metrics/external_metrics.h"
@@ -243,7 +244,7 @@
     ::metrics::MetricsLogUploader::MetricServiceType service_type,
     const ::metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
   return std::unique_ptr<::metrics::MetricsLogUploader>(
-      new ::metrics::NetMetricsLogUploader(request_context_, server_url,
+      new ::metrics::NetMetricsLogUploader(url_loader_factory_, server_url,
                                            insecure_server_url, mime_type,
                                            service_type, on_upload_complete));
 }
@@ -274,7 +275,7 @@
 
 CastMetricsServiceClient::CastMetricsServiceClient(
     PrefService* pref_service,
-    net::URLRequestContextGetter* request_context)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : pref_service_(pref_service),
       client_info_loaded_(false),
 #if defined(OS_LINUX)
@@ -282,7 +283,7 @@
       platform_metrics_(nullptr),
 #endif  // defined(OS_LINUX)
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      request_context_(request_context) {
+      url_loader_factory_(url_loader_factory) {
 }
 
 CastMetricsServiceClient::~CastMetricsServiceClient() {
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.h b/chromecast/browser/metrics/cast_metrics_service_client.h
index 8d0d0d6..7b245e3 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.h
+++ b/chromecast/browser/metrics/cast_metrics_service_client.h
@@ -30,9 +30,9 @@
 class MetricsStateManager;
 }  // namespace metrics
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+}
 
 namespace chromecast {
 namespace metrics {
@@ -42,8 +42,9 @@
 class CastMetricsServiceClient : public ::metrics::MetricsServiceClient,
                                  public ::metrics::EnabledStateProvider {
  public:
-  CastMetricsServiceClient(PrefService* pref_service,
-                           net::URLRequestContextGetter* request_context);
+  CastMetricsServiceClient(
+      PrefService* pref_service,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   ~CastMetricsServiceClient() override;
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
@@ -105,7 +106,7 @@
   std::unique_ptr<::metrics::MetricsStateManager> metrics_state_manager_;
   std::unique_ptr<::metrics::MetricsService> metrics_service_;
   std::unique_ptr<::metrics::EnabledStateProvider> enabled_state_provider_;
-  net::URLRequestContextGetter* const request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CastMetricsServiceClient);
 };
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 0ac444f..4be99e7 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -307,6 +307,10 @@
 // Enables the Cast Receiver.
 const char kEnableCastReceiver[] = "enable-cast-receiver";
 
+// Enables the experimental chromevox developer option.
+const char kEnableChromevoxDeveloperOption[] =
+    "enable-chromevox-developer-option";
+
 // Enables consumer kiosk mode for Chrome OS.
 const char kEnableConsumerKiosk[] = "enable-consumer-kiosk";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 9080de02..0e5c6ef 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -91,6 +91,7 @@
 CHROMEOS_EXPORT extern const char kEnableArcOobeOptinNoSkip[];
 CHROMEOS_EXPORT extern const char kEnableCaptivePortalRandomUrl[];
 CHROMEOS_EXPORT extern const char kEnableCastReceiver[];
+CHROMEOS_EXPORT extern const char kEnableChromevoxDeveloperOption[];
 CHROMEOS_EXPORT extern const char kEnableConsumerKiosk[];
 CHROMEOS_EXPORT extern const char kEnableDataSaverPrompt[];
 CHROMEOS_EXPORT extern const char kEnableDemoMode[];
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.cc b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
index b5e75bd..2e5fba90 100644
--- a/chromeos/services/assistant/platform/audio_output_provider_impl.cc
+++ b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
@@ -137,16 +137,16 @@
     assistant_client::OutputStreamType focused_stream) {}
 
 float VolumeControlImpl::GetSystemVolume() {
-  return volume_;
+  return volume_ * 1.0 / 100.0;
 }
 
 void VolumeControlImpl::SetSystemVolume(float new_volume, bool user_initiated) {
-  volume_control_ptr_->SetVolume(new_volume, user_initiated);
+  volume_control_ptr_->SetVolume(new_volume * 100.0, user_initiated);
 }
 
 float VolumeControlImpl::GetAlarmVolume() {
   // TODO(muyuanli): implement.
-  return 100.0f;
+  return 1.0f;
 }
 
 void VolumeControlImpl::SetAlarmVolume(float new_volume, bool user_initiated) {
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 7669483c..48e2f92e 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -10,9 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/password_autofill_agent.h"
@@ -168,23 +166,6 @@
   }
 }
 
-// Returns the number of characters the user may type while password generation
-// is offered. Once the user has typed more than the given number, a password
-// generation popup is removed.
-// TODO(crbug.com/859472) Delete this function once we know a good value from
-// the field trial.
-size_t GetMaximumOfferSize() {
-  std::string string_value = base::GetFieldTrialParamValue(
-      "PasswordGenerationMaximumOfferSize", "maximum_offer_size");
-  size_t parsed_value = 0;
-  if (!base::StringToSizeT(string_value, &parsed_value)) {
-    // This is the historic default value and remains in place for the time
-    // being. The hypothesis is, though, that 0 would be a better default.
-    return 5;
-  }
-  return parsed_value;
-}
-
 }  // namespace
 
 PasswordGenerationAgent::AccountCreationFormData::AccountCreationFormData(
@@ -212,8 +193,7 @@
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kShowAutofillSignatures)),
       password_agent_(password_agent),
-      binding_(this),
-      maximum_offer_size_(GetMaximumOfferSize()) {
+      binding_(this) {
   LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_);
   registry->AddInterface(base::BindRepeating(
       &PasswordGenerationAgent::BindRequest, base::Unretained(this)));
@@ -377,6 +357,9 @@
 
 void PasswordGenerationAgent::GeneratedPasswordAccepted(
     const base::string16& password) {
+  // static cast is workaround for linker error.
+  DCHECK_LE(static_cast<size_t>(kMinimumLengthForEditedPassword),
+            password.size());
   password_is_generated_ = true;
   password_edited_ = false;
   password_generation::LogPasswordGenerationEvent(
@@ -591,7 +574,8 @@
   }
 
   if (password_is_generated_) {
-    if (generation_element_.Value().IsEmpty()) {
+    if (generation_element_.Value().length() <
+        kMinimumLengthForEditedPassword) {
       PasswordNoLongerGenerated();
     } else {
       generation_element_.SetShouldRevealPassword(true);
@@ -600,11 +584,11 @@
     return true;
   }
 
-  // Assume that if the password field has less than maximum_offer_size_
-  // characters then the user is not finished typing their password and display
-  // the password suggestion.
+  // Assume that if the password field has less than
+  // |kMaximumCharsForGenerationOffer| characters then the user is not finished
+  // typing their password and display the password suggestion.
   if (!element->IsReadOnly() && element->IsEnabled() &&
-      element->Value().length() <= maximum_offer_size_) {
+      element->Value().length() <= kMaximumCharsForGenerationOffer) {
     MaybeOfferAutomaticGeneration();
     return true;
   }
@@ -627,32 +611,34 @@
     return false;
   }
 
-  if (element.Value().IsEmpty()) {
-    // The call may pop up a generation prompt.
-    MaybeOfferAutomaticGeneration();
-    // Tell the browser that the state isn't "editing" anymore. The browser
-    // should hide the editing prompt if it wasn't replaced above.
-    if (password_is_generated_) {
-      // User generated a password and then deleted it.
-      PasswordNoLongerGenerated();
-    }
-  } else if (password_is_generated_) {
-    password_edited_ = true;
-    // Mirror edits to any confirmation password fields.
-    CopyElementValueToOtherInputElements(&element,
-        &generation_form_data_->password_elements);
-    std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
-    if (presaved_form) {
-      GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form);
-    }
-  } else if (element.Value().length() > maximum_offer_size_) {
+  if (!password_is_generated_ &&
+      element.Value().length() > kMaximumCharsForGenerationOffer) {
     // User has rejected the feature and has started typing a password.
     GenerationRejectedByTyping();
   } else {
-    // Password isn't generated and there are fewer than maximum_offer_size_
-    // characters typed, so keep offering the password. Note this function
-    // will just keep the previous popup if one is already showing.
-    MaybeOfferAutomaticGeneration();
+    const bool leave_editing_state =
+        password_is_generated_ &&
+        element.Value().length() < kMinimumLengthForEditedPassword;
+    if (!password_is_generated_ || leave_editing_state) {
+      // The call may pop up a generation prompt, replacing the editing prompt
+      // if it was previously shown.
+      MaybeOfferAutomaticGeneration();
+    }
+    if (leave_editing_state) {
+      // Tell the browser that the state isn't "editing" anymore. The browser
+      // should hide the editing prompt if it wasn't replaced above.
+      PasswordNoLongerGenerated();
+    } else if (password_is_generated_) {
+      password_edited_ = true;
+      // Mirror edits to any confirmation password fields.
+      CopyElementValueToOtherInputElements(
+          &element, &generation_form_data_->password_elements);
+      std::unique_ptr<PasswordForm> presaved_form(
+          CreatePasswordFormToPresave());
+      if (presaved_form) {
+        GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form);
+      }
+    }
   }
   return true;
 }
@@ -712,8 +698,11 @@
     password.SetAutofillState(WebAutofillState::kNotFilled);
   password_generation::LogPasswordGenerationEvent(
       password_generation::PASSWORD_DELETED);
-  CopyElementValueToOtherInputElements(
-      &generation_element_, &generation_form_data_->password_elements);
+  // Clear all other password fields.
+  for (WebInputElement& element : generation_form_data_->password_elements) {
+    if (generation_element_ != element)
+      element.SetAutofillValue(blink::WebString());
+  }
   std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
   if (presaved_form)
     GetPasswordManagerClient()->PasswordNoLongerGenerated(*presaved_form);
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index 74a2a16b..a5f0a8b2 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -35,6 +35,15 @@
 class PasswordGenerationAgent : public content::RenderFrameObserver,
                                 public mojom::PasswordGenerationAgent {
  public:
+  // Maximum number of characters typed by user while the generation is still
+  // offered. When the (kMaximumCharsForGenerationOffer + 1)-th character is
+  // typed, the generation becomes unavailable.
+  static const size_t kMaximumCharsForGenerationOffer = 5;
+
+  // User can edit the generated password. If the length falls below this value,
+  // the password is no longer considered generated.
+  static const size_t kMinimumLengthForEditedPassword = 4;
+
   PasswordGenerationAgent(content::RenderFrame* render_frame,
                           PasswordAutofillAgent* password_agent,
                           blink::AssociatedInterfaceRegistry* registry);
@@ -64,14 +73,7 @@
   // Called right before PasswordAutofillAgent filled |password_element|.
   void OnFieldAutofilled(const blink::WebInputElement& password_element);
 
-  // The length that a password can be before the UI is hidden.
-  size_t maximum_offer_size() const { return maximum_offer_size_; }
-
 #if defined(UNIT_TEST)
-  void set_maximum_offer_size_for_testing(size_t maximum_offer_size) {
-    maximum_offer_size_ = maximum_offer_size;
-  }
-
   // This method requests the autofill::mojom::PasswordManagerClient which binds
   // requests the binding if it wasn't bound yet.
   void RequestPasswordManagerClientForTesting() { GetPasswordManagerClient(); }
@@ -228,9 +230,6 @@
 
   mojo::AssociatedBinding<mojom::PasswordGenerationAgent> binding_;
 
-  // The length that a password can be before the UI is hidden.
-  size_t maximum_offer_size_;
-
   DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgent);
 };
 
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 0d3e6a5a..0dc8d8c 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -465,6 +465,7 @@
     "webdata/autofill_profile_sync_bridge_unittest.cc",
     "webdata/autofill_profile_sync_difference_tracker_unittest.cc",
     "webdata/autofill_profile_syncable_service_unittest.cc",
+    "webdata/autofill_sync_bridge_util_unittest.cc",
     "webdata/autofill_table_unittest.cc",
     "webdata/autofill_wallet_metadata_sync_bridge_unittest.cc",
     "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc
index 330cf8b..9bb74de 100644
--- a/components/autofill/core/browser/autofill_data_util.cc
+++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -16,6 +16,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "third_party/icu/source/common/unicode/uscript.h"
@@ -240,6 +241,13 @@
 
 }  // namespace
 
+std::string TruncateUTF8(const std::string& data) {
+  std::string trimmed_value;
+  base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
+                               &trimmed_value);
+  return trimmed_value;
+}
+
 bool IsCreditCardExpirationType(ServerFieldType type) {
   return type == CREDIT_CARD_EXP_MONTH ||
          type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
diff --git a/components/autofill/core/browser/autofill_data_util.h b/components/autofill/core/browser/autofill_data_util.h
index 0e8ab97..ee3ede76 100644
--- a/components/autofill/core/browser/autofill_data_util.h
+++ b/components/autofill/core/browser/autofill_data_util.h
@@ -23,6 +23,10 @@
   base::string16 family;
 };
 
+// Truncates a string to the nearest UTF-8 character that will leave
+// the string less than or equal to the specified byte size.
+std::string TruncateUTF8(const std::string& data);
+
 bool IsCreditCardExpirationType(ServerFieldType type);
 
 // Used to map Chrome card issuer networks to Payment Request API basic card
diff --git a/components/autofill/core/browser/autofill_profile_sync_util.cc b/components/autofill/core/browser/autofill_profile_sync_util.cc
index f81dc6f..c7af768d 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -7,6 +7,7 @@
 #include "base/guid.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/country_names.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -16,19 +17,13 @@
 
 using base::UTF16ToUTF8;
 using base::UTF8ToUTF16;
+using autofill::data_util::TruncateUTF8;
 using sync_pb::AutofillProfileSpecifics;
 using syncer::EntityData;
 
 namespace autofill {
 namespace {
 
-std::string TruncateUTF8(const std::string& data) {
-  std::string trimmed_value;
-  base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
-                               &trimmed_value);
-  return trimmed_value;
-}
-
 bool IsAutofillProfileSpecificsValid(
     const AutofillProfileSpecifics& specifics) {
   return base::IsValidGUID(specifics.guid());
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index 48721528..3abf1bc 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -36,6 +36,8 @@
 
 namespace {
 
+const int kValidityStateBitfield = 1984;
+
 std::string GetRandomCardNumber() {
   const size_t length = 16;
   std::string value;
@@ -332,6 +334,50 @@
   return profile;
 }
 
+AutofillProfile GetServerProfile() {
+  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "id1");
+  // Note: server profiles don't have email addresses and only have full names.
+  SetProfileInfo(&profile, "", "", "", "", "Google, Inc.", "123 Fake St.",
+                 "Apt. 42", "Mountain View", "California", "94043", "US",
+                 "1.800.555.1234");
+
+  profile.SetInfo(NAME_FULL, ASCIIToUTF16("John K. Doe"), "en");
+  profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("CEDEX"));
+  profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                     ASCIIToUTF16("Santa Clara"));
+
+  profile.set_language_code("en");
+  profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
+  profile.set_use_count(7);
+  profile.set_use_date(base::Time::FromTimeT(54321));
+
+  profile.GenerateServerProfileIdentifier();
+
+  return profile;
+}
+
+AutofillProfile GetServerProfile2() {
+  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "id2");
+  // Note: server profiles don't have email addresses.
+  SetProfileInfo(&profile, "", "", "", "", "Main, Inc.", "4323 Wrong St.",
+                 "Apt. 1032", "Sunnyvale", "California", "10011", "US",
+                 "+1 514-123-1234");
+
+  profile.SetInfo(NAME_FULL, ASCIIToUTF16("Jim S. Bristow"), "en");
+  profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("XEDEC"));
+  profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                     ASCIIToUTF16("Santa Monica"));
+
+  profile.set_language_code("en");
+  profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
+  profile.set_use_count(14);
+  profile.set_use_date(base::Time::FromTimeT(98765));
+
+  profile.GenerateServerProfileIdentifier();
+
+  return profile;
+}
+
 CreditCard GetCreditCard() {
   CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
   SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
@@ -363,6 +409,7 @@
   test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
                           "2109" /* Mastercard */, "12", "2020", "1");
   credit_card.SetNetworkForMaskedCard(kMasterCard);
+  credit_card.set_card_type(CreditCard::CARD_TYPE_CREDIT);
   return credit_card;
 }
 
@@ -371,6 +418,7 @@
   test::SetCreditCardInfo(&credit_card, "Justin Thyme", "8431" /* Amex */, "9",
                           "2020", "1");
   credit_card.SetNetworkForMaskedCard(kAmericanExpressCard);
+  credit_card.set_card_type(CreditCard::CARD_TYPE_PREPAID);
   return credit_card;
 }
 
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h
index 38077c0..2ff459a 100644
--- a/components/autofill/core/browser/autofill_test_utils.h
+++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -107,6 +107,12 @@
 // Returns a verified profile full of dummy info, different to the above.
 AutofillProfile GetVerifiedProfile2();
 
+// Returns a server profile full of dummy info.
+AutofillProfile GetServerProfile();
+
+// Returns a server profile full of dummy info, different to the above.
+AutofillProfile GetServerProfile2();
+
 // Returns a credit card full of dummy info.
 CreditCard GetCreditCard();
 
diff --git a/components/autofill/core/browser/form_field.cc b/components/autofill/core/browser/form_field.cc
index c8d7bf1..3328e18 100644
--- a/components/autofill/core/browser/form_field.cc
+++ b/components/autofill/core/browser/form_field.cc
@@ -70,7 +70,8 @@
   ParseFormFieldsPass(PhoneField::Parse, processed_fields, &field_candidates);
 
   // Address pass.
-  ParseFormFieldsPass(AddressField::Parse, processed_fields, &field_candidates);
+  ParseFormFieldsPass(autofill::AddressField::Parse, processed_fields,
+                      &field_candidates);
 
   // Credit card pass.
   ParseFormFieldsPass(CreditCardField::Parse, processed_fields,
diff --git a/components/autofill/core/browser/test_event_waiter.h b/components/autofill/core/browser/test_event_waiter.h
index b7f7102..be100f8 100644
--- a/components/autofill/core/browser/test_event_waiter.h
+++ b/components/autofill/core/browser/test_event_waiter.h
@@ -31,7 +31,7 @@
 class EventWaiter {
  public:
   explicit EventWaiter(
-      std::list<Event> event_sequence,
+      std::list<Event> expected_event_sequence,
       base::TimeDelta timeout = base::TimeDelta::FromSeconds(0));
   ~EventWaiter();
 
@@ -44,16 +44,16 @@
   void OnEvent(Event event);
 
  private:
-  std::list<Event> events_;
+  std::list<Event> expected_events_;
   base::RunLoop run_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(EventWaiter);
 };
 
 template <typename Event>
-EventWaiter<Event>::EventWaiter(std::list<Event> event_sequence,
+EventWaiter<Event>::EventWaiter(std::list<Event> expected_event_sequence,
                                 base::TimeDelta timeout)
-    : events_(std::move(event_sequence)) {
+    : expected_events_(std::move(expected_event_sequence)) {
   if (!timeout.is_zero()) {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, run_loop_.QuitClosure(), timeout);
@@ -65,23 +65,23 @@
 
 template <typename Event>
 bool EventWaiter<Event>::Wait() {
-  if (events_.empty())
+  if (expected_events_.empty())
     return true;
 
   DCHECK(!run_loop_.running());
   run_loop_.Run();
-  return events_.empty();
+  return expected_events_.empty();
 }
 
 template <typename Event>
-void EventWaiter<Event>::OnEvent(Event event) {
-  if (events_.empty())
+void EventWaiter<Event>::OnEvent(Event actual_event) {
+  if (expected_events_.empty())
     return;
 
-  ASSERT_EQ(events_.front(), event);
-  events_.pop_front();
+  ASSERT_EQ(expected_events_.front(), actual_event);
+  expected_events_.pop_front();
   // Only quit the loop if no other events are expected.
-  if (events_.empty() && run_loop_.running())
+  if (expected_events_.empty() && run_loop_.running())
     run_loop_.Quit();
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc b/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc
index 4b7b7d7..2bd936a4 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.cc
@@ -16,4 +16,32 @@
   return CreditCard(CreditCard::MASKED_SERVER_CARD, server_id);
 }
 
+sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForCard(
+    const std::string& specifics_id,
+    const std::string& billing_address_id) {
+  sync_pb::AutofillWalletSpecifics wallet_specifics;
+  wallet_specifics.set_type(
+      sync_pb::AutofillWalletSpecifics_WalletInfoType::
+          AutofillWalletSpecifics_WalletInfoType_MASKED_CREDIT_CARD);
+
+  sync_pb::WalletMaskedCreditCard* card_specifics =
+      wallet_specifics.mutable_masked_card();
+  card_specifics->set_id(specifics_id);
+  card_specifics->set_billing_address_id(billing_address_id);
+  return wallet_specifics;
+}
+
+sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForAddress(
+    const std::string& specifics_id) {
+  sync_pb::AutofillWalletSpecifics wallet_specifics;
+  wallet_specifics.set_type(
+      sync_pb::AutofillWalletSpecifics_WalletInfoType::
+          AutofillWalletSpecifics_WalletInfoType_POSTAL_ADDRESS);
+
+  sync_pb::WalletPostalAddress* profile_specifics =
+      wallet_specifics.mutable_address();
+  profile_specifics->set_id(specifics_id);
+  return wallet_specifics;
+}
+
 }  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h b/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h
index 7eb8bf4..0780855 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h
@@ -9,6 +9,7 @@
 
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
+#include "components/sync/protocol/sync.pb.h"
 
 namespace autofill {
 
@@ -16,6 +17,13 @@
 
 CreditCard CreateServerCreditCard(const std::string& server_id);
 
+sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForAddress(
+    const std::string& specifics_id);
+
+sync_pb::AutofillWalletSpecifics CreateAutofillWalletSpecificsForCard(
+    const std::string& specifics_id,
+    const std::string& billing_address_id = "");
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_TEST_UTIL_H_
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
index fc0a4205..3bd0f3e 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
@@ -7,34 +7,39 @@
 #include "base/base64.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/sync/model/entity_data.h"
 
+using autofill::data_util::TruncateUTF8;
 using sync_pb::AutofillWalletSpecifics;
 using syncer::EntityData;
 
 namespace autofill {
 namespace {
-std::string TruncateUTF8(const std::string& data) {
-  std::string trimmed_value;
-  base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
-                               &trimmed_value);
-  return trimmed_value;
-}
-
 sync_pb::WalletMaskedCreditCard::WalletCardStatus LocalToServerStatus(
     const CreditCard& card) {
   switch (card.GetServerStatus()) {
     case CreditCard::OK:
       return sync_pb::WalletMaskedCreditCard::VALID;
     case CreditCard::EXPIRED:
-    default:
       return sync_pb::WalletMaskedCreditCard::EXPIRED;
   }
 }
 
+CreditCard::ServerStatus ServerToLocalStatus(
+    sync_pb::WalletMaskedCreditCard::WalletCardStatus status) {
+  switch (status) {
+    case sync_pb::WalletMaskedCreditCard::VALID:
+      return CreditCard::OK;
+    case sync_pb::WalletMaskedCreditCard::EXPIRED:
+      return CreditCard::EXPIRED;
+  }
+}
+
 sync_pb::WalletMaskedCreditCard::WalletCardType WalletCardTypeFromCardNetwork(
     const std::string& network) {
   if (network == kAmericanExpressCard)
@@ -54,6 +59,31 @@
   return sync_pb::WalletMaskedCreditCard::UNKNOWN;
 }
 
+const char* CardNetworkFromWalletCardType(
+    sync_pb::WalletMaskedCreditCard::WalletCardType type) {
+  switch (type) {
+    case sync_pb::WalletMaskedCreditCard::AMEX:
+      return kAmericanExpressCard;
+    case sync_pb::WalletMaskedCreditCard::DISCOVER:
+      return kDiscoverCard;
+    case sync_pb::WalletMaskedCreditCard::JCB:
+      return kJCBCard;
+    case sync_pb::WalletMaskedCreditCard::MASTER_CARD:
+      return kMasterCard;
+    case sync_pb::WalletMaskedCreditCard::UNIONPAY:
+      return kUnionPay;
+    case sync_pb::WalletMaskedCreditCard::VISA:
+      return kVisaCard;
+
+    // These aren't supported by the client, so just declare a generic card.
+    case sync_pb::WalletMaskedCreditCard::MAESTRO:
+    case sync_pb::WalletMaskedCreditCard::SOLO:
+    case sync_pb::WalletMaskedCreditCard::SWITCH:
+    case sync_pb::WalletMaskedCreditCard::UNKNOWN:
+      return kGenericCard;
+  }
+}
+
 sync_pb::WalletMaskedCreditCard::WalletCardClass WalletCardClassFromCardType(
     CreditCard::CardType card_type) {
   switch (card_type) {
@@ -63,11 +93,25 @@
       return sync_pb::WalletMaskedCreditCard::DEBIT;
     case CreditCard::CARD_TYPE_PREPAID:
       return sync_pb::WalletMaskedCreditCard::PREPAID;
-    default:
+    case CreditCard::CARD_TYPE_UNKNOWN:
       return sync_pb::WalletMaskedCreditCard::UNKNOWN_CARD_CLASS;
   }
 }
 
+CreditCard::CardType CardTypeFromWalletCardClass(
+    sync_pb::WalletMaskedCreditCard::WalletCardClass card_class) {
+  switch (card_class) {
+    case sync_pb::WalletMaskedCreditCard::CREDIT:
+      return CreditCard::CARD_TYPE_CREDIT;
+    case sync_pb::WalletMaskedCreditCard::DEBIT:
+      return CreditCard::CARD_TYPE_DEBIT;
+    case sync_pb::WalletMaskedCreditCard::PREPAID:
+      return CreditCard::CARD_TYPE_PREPAID;
+    case sync_pb::WalletMaskedCreditCard::UNKNOWN_CARD_CLASS:
+      return CreditCard::CARD_TYPE_UNKNOWN;
+  }
+}
+
 }  // namespace
 
 std::string GetSpecificsIdForEntryServerId(const std::string& server_id) {
@@ -172,6 +216,44 @@
   return entity_data;
 }
 
+AutofillProfile ProfileFromSpecifics(
+    const sync_pb::WalletPostalAddress& address) {
+  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string());
+
+  // AutofillProfile stores multi-line addresses with newline separators.
+  std::vector<base::StringPiece> street_address(
+      address.street_address().begin(), address.street_address().end());
+  profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
+                     base::UTF8ToUTF16(base::JoinString(street_address, "\n")));
+
+  profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name()));
+  profile.SetRawInfo(ADDRESS_HOME_STATE,
+                     base::UTF8ToUTF16(address.address_1()));
+  profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2()));
+  profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                     base::UTF8ToUTF16(address.address_3()));
+  // AutofillProfile doesn't support address_4 ("sub dependent locality").
+  profile.SetRawInfo(ADDRESS_HOME_ZIP,
+                     base::UTF8ToUTF16(address.postal_code()));
+  profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE,
+                     base::UTF8ToUTF16(address.sorting_code()));
+  profile.SetRawInfo(ADDRESS_HOME_COUNTRY,
+                     base::UTF8ToUTF16(address.country_code()));
+  profile.set_language_code(address.language_code());
+
+  // SetInfo instead of SetRawInfo so the constituent pieces will be parsed
+  // for these data types.
+  profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()),
+                  profile.language_code());
+  profile.SetInfo(PHONE_HOME_WHOLE_NUMBER,
+                  base::UTF8ToUTF16(address.phone_number()),
+                  profile.language_code());
+
+  profile.GenerateServerProfileIdentifier();
+
+  return profile;
+}
+
 void SetAutofillWalletSpecificsFromServerCard(
     const CreditCard& card,
     AutofillWalletSpecifics* wallet_specifics) {
@@ -209,4 +291,87 @@
   return entity_data;
 }
 
-}  // namespace autofill
\ No newline at end of file
+CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) {
+  CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id());
+  result.SetNumber(base::UTF8ToUTF16(card.last_four()));
+  result.SetServerStatus(ServerToLocalStatus(card.status()));
+  result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type()));
+  result.set_card_type(CardTypeFromWalletCardClass(card.card_class()));
+  result.SetRawInfo(CREDIT_CARD_NAME_FULL,
+                    base::UTF8ToUTF16(card.name_on_card()));
+  result.SetExpirationMonth(card.exp_month());
+  result.SetExpirationYear(card.exp_year());
+  result.set_billing_address_id(card.billing_address_id());
+  result.set_bank_name(card.bank_name());
+  return result;
+}
+
+void CopyRelevantWalletMetadataFromDisk(
+    const AutofillTable& table,
+    std::vector<CreditCard>* cards_from_server) {
+  std::vector<std::unique_ptr<CreditCard>> cards_on_disk;
+  table.GetServerCreditCards(&cards_on_disk);
+
+  // Since the number of cards is fairly small, the brute-force search is good
+  // enough.
+  for (const auto& saved_card : cards_on_disk) {
+    for (CreditCard& server_card : *cards_from_server) {
+      if (saved_card->server_id() == server_card.server_id()) {
+        // The wallet data doesn't have the use stats. Use the ones present on
+        // disk to not overwrite them with bad data.
+        server_card.set_use_count(saved_card->use_count());
+        server_card.set_use_date(saved_card->use_date());
+
+        // Keep the billing address id of the saved cards only if it points to
+        // a local address.
+        if (saved_card->billing_address_id().length() == kLocalGuidSize) {
+          server_card.set_billing_address_id(saved_card->billing_address_id());
+          break;
+        }
+      }
+    }
+  }
+}
+
+void PopulateWalletCardsAndAddresses(
+    const syncer::EntityChangeList& entity_data,
+    std::vector<CreditCard>* wallet_cards,
+    std::vector<AutofillProfile>* wallet_addresses) {
+  std::map<std::string, std::string> ids;
+
+  for (const syncer::EntityChange& change : entity_data) {
+    DCHECK(change.data().specifics.has_autofill_wallet());
+
+    const sync_pb::AutofillWalletSpecifics& autofill_specifics =
+        change.data().specifics.autofill_wallet();
+
+    switch (autofill_specifics.type()) {
+      case sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD:
+        wallet_cards->push_back(
+            CardFromSpecifics(autofill_specifics.masked_card()));
+        break;
+      case sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS:
+        wallet_addresses->push_back(
+            ProfileFromSpecifics(autofill_specifics.address()));
+
+        // Map the sync billing address id to the profile's id.
+        ids[autofill_specifics.address().id()] =
+            wallet_addresses->back().server_id();
+        break;
+      case sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA:
+      case sync_pb::AutofillWalletSpecifics::UNKNOWN:
+        // Just ignore new entry types that the client doesn't know about.
+        break;
+    }
+  }
+
+  // Set the billing address of the wallet cards to the id of the appropriate
+  // profile.
+  for (CreditCard& card : *wallet_cards) {
+    auto it = ids.find(card.billing_address_id());
+    if (it != ids.end())
+      card.set_billing_address_id(it->second);
+  }
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
index bd5e40c..7207ea7 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
@@ -8,11 +8,13 @@
 #include <memory>
 #include <string>
 
+#include "components/sync/model/entity_change.h"
 #include "components/sync/model/entity_data.h"
 
 namespace autofill {
 
 class AutofillProfile;
+class AutofillTable;
 class CreditCard;
 
 // Returns the wallet specifics id for the specified |server_id|.
@@ -40,6 +42,10 @@
 std::unique_ptr<syncer::EntityData> CreateEntityDataFromAutofillServerProfile(
     const AutofillProfile& address);
 
+// Creates an AutofillProfile from the specified |address| specifics.
+AutofillProfile ProfileFromSpecifics(
+    const sync_pb::WalletPostalAddress& address);
+
 // Sets the fields of the |wallet_specifics| based on the the specified |card|.
 void SetAutofillWalletSpecificsFromServerCard(
     const CreditCard& card,
@@ -49,6 +55,26 @@
 std::unique_ptr<syncer::EntityData> CreateEntityDataFromCard(
     const CreditCard& card);
 
+// Creates an AutofillProfile from the specified |card| specifics.
+CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card);
+
+// TODO(sebsg): This should probably copy the converted state for the address
+// too.
+// Copies the metadata from the local cards (if present) to the corresponding
+// server cards so that they don't get overwritten. This is because the wallet
+// data does not include those. They are handled by the
+// AutofillWalletMetadataSyncBridge.
+void CopyRelevantWalletMetadataFromDisk(
+    const AutofillTable& table,
+    std::vector<CreditCard>* cards_from_server);
+
+// Populates the wallet cards and addresses from the sync data and uses the
+// sync data to link the card to its billing address.
+void PopulateWalletCardsAndAddresses(
+    const ::syncer::EntityChangeList& entity_data,
+    std::vector<CreditCard>* wallet_cards,
+    std::vector<AutofillProfile>* wallet_addresses);
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_SYNC_BRIDGE_UTIL_H_
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
new file mode 100644
index 0000000..b0aacc5
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
@@ -0,0 +1,196 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h"
+
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
+#include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/sync/base/hash_util.h"
+#include "components/sync/model/entity_data.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+using syncer::EntityChange;
+using syncer::EntityData;
+
+class TestAutofillTable : public AutofillTable {
+ public:
+  explicit TestAutofillTable(std::vector<CreditCard> cards_on_disk)
+      : cards_on_disk_(cards_on_disk) {}
+
+  ~TestAutofillTable() override {}
+
+  bool GetServerCreditCards(
+      std::vector<std::unique_ptr<CreditCard>>* cards) const override {
+    for (const auto& card_on_disk : cards_on_disk_)
+      cards->push_back(std::make_unique<CreditCard>(card_on_disk));
+    return true;
+  }
+
+ private:
+  std::vector<CreditCard> cards_on_disk_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillTable);
+};
+
+EntityData SpecificsToEntity(const sync_pb::AutofillWalletSpecifics& specifics,
+                             const std::string& client_tag) {
+  EntityData data;
+  *data.specifics.mutable_autofill_wallet() = specifics;
+  data.client_tag_hash =
+      syncer::GenerateSyncableHash(syncer::AUTOFILL_WALLET_DATA, client_tag);
+  return data;
+}
+
+class AutofillSyncBridgeUtilTest : public testing::Test {
+ public:
+  AutofillSyncBridgeUtilTest() {}
+  ~AutofillSyncBridgeUtilTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillSyncBridgeUtilTest);
+};
+
+// Tests that the link between a card and its billing address from sync is
+// present in the generated Autofill objects.
+TEST_F(AutofillSyncBridgeUtilTest,
+       PopulateWalletCardsAndAddresses_BillingAddressIdTransfer) {
+  // Add an address and a card that has its billing address id set to the
+  // address' id.
+  syncer::EntityChangeList entity_data;
+  std::string address_id("address1");
+  entity_data.push_back(EntityChange::CreateAdd(
+      address_id,
+      SpecificsToEntity(CreateAutofillWalletSpecificsForAddress(address_id),
+                        /*client_tag=*/"address-address1")
+          .PassToPtr()));
+  entity_data.push_back(EntityChange::CreateAdd(
+      "card1",
+      SpecificsToEntity(CreateAutofillWalletSpecificsForCard(
+                            /*id=*/"card1", /*billing_address_id=*/address_id),
+                        /*client_tag=*/"card-card1")
+          .PassToPtr()));
+
+  std::vector<CreditCard> wallet_cards;
+  std::vector<AutofillProfile> wallet_addresses;
+  PopulateWalletCardsAndAddresses(entity_data, &wallet_cards,
+                                  &wallet_addresses);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+  ASSERT_EQ(1U, wallet_addresses.size());
+
+  // Make sure the card's billing address id is equal to the address' server id.
+  EXPECT_EQ(wallet_addresses.back().server_id(),
+            wallet_cards.back().billing_address_id());
+}
+
+// Verify that the billing address id from the card saved on disk is kept if it
+// is a local profile guid.
+TEST_F(AutofillSyncBridgeUtilTest,
+       CopyRelevantWalletMetadataFromDisk_KeepLocalAddresses) {
+  std::vector<CreditCard> cards_on_disk;
+  std::vector<CreditCard> wallet_cards;
+
+  // Create a local profile to be used as a billing address.
+  AutofillProfile billing_address;
+
+  // Create a card on disk that refers to that local profile as its billing
+  // address.
+  cards_on_disk.push_back(CreditCard());
+  cards_on_disk.back().set_billing_address_id(billing_address.guid());
+
+  // Create a card pulled from wallet with the same id, but a different billing
+  // address id.
+  wallet_cards.push_back(CreditCard(cards_on_disk.back()));
+  wallet_cards.back().set_billing_address_id("1234");
+
+  // Setup the TestAutofillTable with the cards_on_disk.
+  TestAutofillTable table(cards_on_disk);
+
+  CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+
+  // Make sure the wallet card replace its billing address id for the one that
+  // was saved on disk.
+  EXPECT_EQ(cards_on_disk.back().billing_address_id(),
+            wallet_cards.back().billing_address_id());
+}
+
+// Verify that the billing address id from the card saved on disk is overwritten
+// if it does not refer to a local profile.
+TEST_F(AutofillSyncBridgeUtilTest,
+       CopyRelevantWalletMetadataFromDisk_OverwriteOtherAddresses) {
+  std::string old_billing_id = "1234";
+  std::string new_billing_id = "9876";
+  std::vector<CreditCard> cards_on_disk;
+  std::vector<CreditCard> wallet_cards;
+
+  // Create a card on disk that does not refer to a local profile (which have 36
+  // chars ids).
+  cards_on_disk.push_back(CreditCard());
+  cards_on_disk.back().set_billing_address_id(old_billing_id);
+
+  // Create a card pulled from wallet with the same id, but a different billing
+  // address id.
+  wallet_cards.push_back(CreditCard(cards_on_disk.back()));
+  wallet_cards.back().set_billing_address_id(new_billing_id);
+
+  // Setup the TestAutofillTable with the cards_on_disk.
+  TestAutofillTable table(cards_on_disk);
+
+  CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+
+  // Make sure the local address billing id that was saved on disk did not
+  // replace the new one.
+  EXPECT_EQ(new_billing_id, wallet_cards.back().billing_address_id());
+}
+
+// Verify that the use stats on disk are kept when server cards are synced.
+TEST_F(AutofillSyncBridgeUtilTest,
+       CopyRelevantWalletMetadataFromDisk_KeepUseStats) {
+  TestAutofillClock test_clock;
+  base::Time arbitrary_time = base::Time::FromDoubleT(25);
+  base::Time disk_time = base::Time::FromDoubleT(10);
+  test_clock.SetNow(arbitrary_time);
+
+  std::vector<CreditCard> cards_on_disk;
+  std::vector<CreditCard> wallet_cards;
+
+  // Create a card on disk with specific use stats.
+  cards_on_disk.push_back(CreditCard());
+  cards_on_disk.back().set_use_count(3U);
+  cards_on_disk.back().set_use_date(disk_time);
+
+  // Create a card pulled from wallet with the same id, but a different billing
+  // address id.
+  wallet_cards.push_back(CreditCard());
+  wallet_cards.back().set_use_count(10U);
+
+  // Setup the TestAutofillTable with the cards_on_disk.
+  TestAutofillTable table(cards_on_disk);
+
+  CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+
+  // Make sure the use stats from disk were kept
+  EXPECT_EQ(3U, wallet_cards.back().use_count());
+  EXPECT_EQ(disk_time, wallet_cards.back().use_date());
+}
+
+}  // namespace
+}  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index ce6c6172..ce6167f 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -2394,6 +2394,7 @@
     syncer::ModelType model_type) const {
   return (model_type == syncer::AUTOFILL ||
           model_type == syncer::AUTOFILL_PROFILE ||
+          model_type == syncer::AUTOFILL_WALLET_DATA ||
           model_type == syncer::AUTOFILL_WALLET_METADATA);
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index bed8074..3cc9fa48e 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -8,6 +8,7 @@
 
 #include "base/base64.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_profile.h"
@@ -17,8 +18,10 @@
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/sync/model/entity_data.h"
 #include "components/sync/model/mutable_data_batch.h"
+#include "components/sync/model/sync_merge_result.h"
 #include "components/sync/model_impl/client_tag_based_model_type_processor.h"
 #include "components/sync/model_impl/sync_metadata_store_change_list.h"
 
@@ -75,7 +78,11 @@
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor,
     AutofillWebDataBackend* web_data_backend)
     : ModelTypeSyncBridge(std::move(change_processor)),
-      web_data_backend_(web_data_backend) {}
+      web_data_backend_(web_data_backend) {
+  DCHECK(web_data_backend_);
+
+  LoadMetadata();
+}
 
 AutofillWalletSyncBridge::~AutofillWalletSyncBridge() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -91,14 +98,14 @@
 base::Optional<syncer::ModelError> AutofillWalletSyncBridge::MergeSyncData(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_data) {
-  return ApplySyncChanges(std::move(metadata_change_list),
-                          std::move(entity_data));
+  SetSyncData(entity_data, /*is_initial_data=*/true);
+  return base::nullopt;
 }
 
 base::Optional<syncer::ModelError> AutofillWalletSyncBridge::ApplySyncChanges(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_data) {
-  NOTIMPLEMENTED();
+  SetSyncData(entity_data, /*is_initial_data=*/false);
   return base::nullopt;
 }
 
@@ -149,8 +156,132 @@
       entity_data.specifics.autofill_wallet());
 }
 
+void AutofillWalletSyncBridge::SetSyncData(
+    const syncer::EntityChangeList& entity_data,
+    bool is_initial_data) {
+  std::vector<CreditCard> wallet_cards;
+  std::vector<AutofillProfile> wallet_addresses;
+  PopulateWalletCardsAndAddresses(entity_data, &wallet_cards,
+                                  &wallet_addresses);
+
+  // Users can set billing address of the server credit card locally, but that
+  // information does not propagate to either Chrome Sync or Google Payments
+  // server. To preserve user's preferred billing address and most recent use
+  // stats, copy them from disk into |wallet_cards|.
+  AutofillTable* table = GetAutofillTable();
+  CopyRelevantWalletMetadataFromDisk(*table, &wallet_cards);
+
+  // In the common case, the database won't have changed. Committing an update
+  // to the database will require at least one DB page write and will schedule
+  // a fsync. To avoid this I/O, it should be more efficient to do a read and
+  // only do the writes if something changed.
+  std::vector<std::unique_ptr<CreditCard>> existing_cards;
+  table->GetServerCreditCards(&existing_cards);
+  AutofillWalletDiff cards_diff =
+      ComputeAutofillWalletDiff(existing_cards, wallet_cards);
+  if (!cards_diff.IsEmpty())
+    table->SetServerCreditCards(wallet_cards);
+
+  std::vector<std::unique_ptr<AutofillProfile>> existing_addresses;
+  table->GetServerProfiles(&existing_addresses);
+  AutofillWalletDiff addresses_diff =
+      ComputeAutofillWalletDiff(existing_addresses, wallet_addresses);
+  if (!addresses_diff.IsEmpty())
+    table->SetServerProfiles(wallet_addresses);
+
+  if (!is_initial_data) {
+    UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsAdded",
+                             cards_diff.items_added);
+    UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsRemoved",
+                             cards_diff.items_removed);
+    UMA_HISTOGRAM_COUNTS_100("Autofill.WalletCardsAddedOrRemoved",
+                             cards_diff.items_added + cards_diff.items_removed);
+
+    UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddressesAdded",
+                             addresses_diff.items_added);
+    UMA_HISTOGRAM_COUNTS_100("Autofill.WalletAddressesRemoved",
+                             addresses_diff.items_removed);
+    UMA_HISTOGRAM_COUNTS_100(
+        "Autofill.WalletAddressesAddedOrRemoved",
+        addresses_diff.items_added + addresses_diff.items_removed);
+  }
+
+  if (web_data_backend_ && (!cards_diff.IsEmpty() || !addresses_diff.IsEmpty()))
+    web_data_backend_->NotifyOfMultipleAutofillChanges();
+}
+
+// static
+template <class Item>
+AutofillWalletSyncBridge::AutofillWalletDiff
+AutofillWalletSyncBridge::ComputeAutofillWalletDiff(
+    const std::vector<std::unique_ptr<Item>>& old_data,
+    const std::vector<Item>& new_data) {
+  // Build vectors of pointers, so that we can mutate (sort) them.
+  std::vector<const Item*> old_ptrs;
+  old_ptrs.reserve(old_data.size());
+  for (const std::unique_ptr<Item>& old_item : old_data)
+    old_ptrs.push_back(old_item.get());
+  std::vector<const Item*> new_ptrs;
+  new_ptrs.reserve(new_data.size());
+  for (const Item& new_item : new_data)
+    new_ptrs.push_back(&new_item);
+
+  // Sort our vectors.
+  auto compare = [](const Item* lhs, const Item* rhs) {
+    return lhs->Compare(*rhs) < 0;
+  };
+  std::sort(old_ptrs.begin(), old_ptrs.end(), compare);
+  std::sort(new_ptrs.begin(), new_ptrs.end(), compare);
+
+  // Walk over both of them and count added/removed elements.
+  AutofillWalletDiff result;
+  auto old_it = old_ptrs.begin();
+  auto new_it = new_ptrs.begin();
+  while (old_it != old_ptrs.end()) {
+    if (new_it == new_ptrs.end()) {
+      result.items_removed += std::distance(old_it, old_ptrs.end());
+      break;
+    }
+    int cmp = (*old_it)->Compare(**new_it);
+    if (cmp < 0) {
+      ++result.items_removed;
+      ++old_it;
+    } else if (cmp == 0) {
+      ++old_it;
+      ++new_it;
+    } else {
+      ++result.items_added;
+      ++new_it;
+    }
+  }
+  result.items_added += std::distance(new_it, new_ptrs.end());
+
+  DCHECK_EQ(old_data.size() + result.items_added - result.items_removed,
+            new_data.size());
+
+  return result;
+}
+
 AutofillTable* AutofillWalletSyncBridge::GetAutofillTable() {
   return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase());
 }
 
+void AutofillWalletSyncBridge::LoadMetadata() {
+  if (!web_data_backend_ || !web_data_backend_->GetDatabase() ||
+      !GetAutofillTable()) {
+    change_processor()->ReportError(
+        {FROM_HERE, "Failed to load AutofillWebDatabase."});
+    return;
+  }
+
+  auto batch = std::make_unique<syncer::MetadataBatch>();
+  if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL_PROFILE,
+                                              batch.get())) {
+    change_processor()->ReportError(
+        {FROM_HERE, "Failed reading autofill metadata from WebDatabase."});
+    return;
+  }
+  change_processor()->ModelReadyToSync(std::move(batch));
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
index 394de20..82d8f40 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
@@ -19,9 +19,11 @@
 
 namespace autofill {
 
+class AutofillProfile;
 class AutofillTable;
 class AutofillWebDataBackend;
 class AutofillWebDataService;
+class CreditCard;
 
 // Sync bridge responsible for propagating local changes to the processor and
 // applying remote changes to the local database.
@@ -59,6 +61,30 @@
   std::string GetStorageKey(const syncer::EntityData& entity_data) override;
 
  private:
+  struct AutofillWalletDiff {
+    int items_added = 0;
+    int items_removed = 0;
+
+    bool IsEmpty() const { return items_added == 0 && items_removed == 0; }
+  };
+
+  // Sets the wallet data from |entity_data| to this client. Records metrics
+  // about added/deleted data if not the |is_initial_data|.
+  void SetSyncData(const syncer::EntityChangeList& entity_data,
+                   bool is_initial_data);
+
+  // Computes a "diff" (items added, items removed) of two vectors of items,
+  // which should be either CreditCard or AutofillProfile. This is used for two
+  // purposes:
+  // 1) Detecting if anything has changed, so that we don't write to disk in the
+  //    common case where nothing has changed.
+  // 2) Recording metrics on the number of added/removed items.
+  // This is exposed as a static method so that it can be tested.
+  template <class Item>
+  static AutofillWalletDiff ComputeAutofillWalletDiff(
+      const std::vector<std::unique_ptr<Item>>& old_data,
+      const std::vector<Item>& new_data);
+
   // Returns the table associated with the |web_data_backend_|.
   AutofillTable* GetAutofillTable();
 
@@ -66,6 +92,10 @@
   // SupportsUserData, so it's guaranteed to outlive |this|.
   AutofillWebDataBackend* const web_data_backend_;
 
+  // Synchronously load sync metadata from the autofill table and pass it to the
+  // processor so that it can start tracking changes.
+  void LoadMetadata();
+
   // The bridge should be used on the same sequence where it is constructed.
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index d702c4f..7513678 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -16,7 +16,10 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/country_names.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h"
 #include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h"
@@ -39,6 +42,7 @@
 using base::ScopedTempDir;
 using sync_pb::AutofillWalletSpecifics;
 using syncer::DataBatch;
+using syncer::EntityChange;
 using syncer::EntityData;
 using syncer::EntityDataPtr;
 using syncer::KeyAndData;
@@ -46,12 +50,6 @@
 using syncer::ModelType;
 using testing::UnorderedElementsAre;
 
-// Non-UTF8 server IDs.
-const char kAddr1ServerId[] = "addr1\xEF\xBF\xBE";
-const char kAddr2ServerId[] = "addr2\xEF\xBF\xBE";
-const char kCard1ServerId[] = "card1\xEF\xBF\xBE";
-const char kCard2ServerId[] = "card2\xEF\xBF\xBE";
-
 // Base64 encodings of the server IDs, used as ids in WalletMetadataSpecifics
 // (these are suitable for syncing, because they are valid UTF-8).
 const char kAddr1SpecificsId[] = "YWRkcjHvv74=";
@@ -86,32 +84,6 @@
   WebDatabase* db_;
 };
 
-AutofillWalletSpecifics CreateAutofillWalletSpecificsForCard(
-    const std::string& specifics_id) {
-  sync_pb::AutofillWalletSpecifics wallet_specifics;
-  wallet_specifics.set_type(
-      sync_pb::AutofillWalletSpecifics_WalletInfoType::
-          AutofillWalletSpecifics_WalletInfoType_MASKED_CREDIT_CARD);
-
-  sync_pb::WalletMaskedCreditCard* card_specifics =
-      wallet_specifics.mutable_masked_card();
-  card_specifics->set_id(specifics_id);
-  return wallet_specifics;
-}
-
-AutofillWalletSpecifics CreateAutofillWalletSpecificsForAddress(
-    const std::string& specifics_id) {
-  sync_pb::AutofillWalletSpecifics wallet_specifics;
-  wallet_specifics.set_type(
-      sync_pb::AutofillWalletSpecifics_WalletInfoType::
-          AutofillWalletSpecifics_WalletInfoType_POSTAL_ADDRESS);
-
-  sync_pb::WalletPostalAddress* address_specifics =
-      wallet_specifics.mutable_address();
-  address_specifics->set_id(specifics_id);
-  return wallet_specifics;
-}
-
 void ExtractAutofillWalletSpecificsFromDataBatch(
     std::unique_ptr<DataBatch> batch,
     std::vector<AutofillWalletSpecifics>* output) {
@@ -220,6 +192,29 @@
         mock_processor_.CreateForwardingProcessor(), &backend_));
   }
 
+  void StartSyncing(
+      const std::vector<AutofillWalletSpecifics>& remote_data = {}) {
+    base::RunLoop loop;
+    syncer::DataTypeActivationRequest request;
+    request.error_handler = base::DoNothing();
+    real_processor_->OnSyncStarting(
+        request,
+        base::BindLambdaForTesting(
+            [&loop](std::unique_ptr<syncer::DataTypeActivationResponse>) {
+              loop.Quit();
+            }));
+    loop.Run();
+
+    // Initialize the processor with initial_sync_done.
+    sync_pb::ModelTypeState state;
+    state.set_initial_sync_done(true);
+    syncer::UpdateResponseDataList initial_updates;
+    for (const AutofillWalletSpecifics& specifics : remote_data) {
+      initial_updates.push_back(SpecificsToUpdateResponse(specifics));
+    }
+    real_processor_->OnUpdateReceived(state, initial_updates);
+  }
+
   EntityData SpecificsToEntity(const AutofillWalletSpecifics& specifics) {
     EntityData data;
     *data.specifics.mutable_autofill_wallet() = specifics;
@@ -241,6 +236,13 @@
     return data;
   }
 
+  syncer::UpdateResponseData SpecificsToUpdateResponse(
+      const AutofillWalletSpecifics& specifics) {
+    syncer::UpdateResponseData data;
+    data.entity = SpecificsToEntity(specifics).PassToPtr();
+    return data;
+  }
+
   AutofillWalletSyncBridge* bridge() { return bridge_.get(); }
 
   syncer::MockModelTypeChangeProcessor& mock_processor() {
@@ -297,27 +299,208 @@
 
 TEST_F(AutofillWalletSyncBridgeTest,
        GetAllDataForDebugging_ShouldReturnAllData) {
-  AutofillProfile address1 = CreateServerProfile(kAddr1ServerId);
-  AutofillProfile address2 = CreateServerProfile(kAddr2ServerId);
+  AutofillProfile address1 = test::GetServerProfile();
+  AutofillProfile address2 = test::GetServerProfile2();
   table()->SetServerProfiles({address1, address2});
-  CreditCard card1 = CreateServerCreditCard(kCard1ServerId);
-  CreditCard card2 = CreateServerCreditCard(kCard2ServerId);
+  CreditCard card1 = test::GetMaskedServerCard();
+  CreditCard card2 = test::GetMaskedServerCardAmex();
   table()->SetServerCreditCards({card1, card2});
 
-  AutofillWalletSpecifics address_specifics1;
-  SetAutofillWalletSpecificsFromServerProfile(address1, &address_specifics1);
-  AutofillWalletSpecifics address_specifics2;
-  SetAutofillWalletSpecificsFromServerProfile(address2, &address_specifics2);
+  AutofillWalletSpecifics profile_specifics1;
+  SetAutofillWalletSpecificsFromServerProfile(address1, &profile_specifics1);
+  AutofillWalletSpecifics profile_specifics2;
+  SetAutofillWalletSpecificsFromServerProfile(address2, &profile_specifics2);
   AutofillWalletSpecifics card_specifics1;
   SetAutofillWalletSpecificsFromServerCard(card1, &card_specifics1);
   AutofillWalletSpecifics card_specifics2;
   SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2);
 
   EXPECT_THAT(GetAllLocalData(),
-              UnorderedElementsAre(EqualsSpecifics(address_specifics1),
-                                   EqualsSpecifics(address_specifics2),
+              UnorderedElementsAre(EqualsSpecifics(profile_specifics1),
+                                   EqualsSpecifics(profile_specifics2),
                                    EqualsSpecifics(card_specifics1),
                                    EqualsSpecifics(card_specifics2)));
 }
 
+// Tests that when a new wallet card and new wallet address are sent by the
+// server, the client only keeps the new data.
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) {
+  // Create one profile and one card on the client.
+  AutofillProfile address1 = test::GetServerProfile();
+  table()->SetServerProfiles({address1});
+  CreditCard card1 = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({card1});
+
+  // Create a different profile and a different card on the server.
+  AutofillProfile address2 = test::GetServerProfile2();
+  AutofillWalletSpecifics profile_specifics2;
+  SetAutofillWalletSpecificsFromServerProfile(address2, &profile_specifics2);
+  CreditCard card2 = test::GetMaskedServerCardAmex();
+  AutofillWalletSpecifics card_specifics2;
+  SetAutofillWalletSpecificsFromServerCard(card2, &card_specifics2);
+
+  StartSyncing({profile_specifics2, card_specifics2});
+
+  // Only the server card should be present on the client.
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(EqualsSpecifics(profile_specifics2),
+                                   EqualsSpecifics(card_specifics2)));
+}
+
+// Tests that when the server sends no cards or address, the client should
+// delete all it's existing data.
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) {
+  // Create one profile and one card on the client.
+  AutofillProfile local_profile = test::GetServerProfile();
+  table()->SetServerProfiles({local_profile});
+  CreditCard local_card = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({local_card});
+
+  StartSyncing({});
+
+  EXPECT_TRUE(GetAllLocalData().empty());
+}
+
+// Test that when the server sends the same address and card as the client has,
+// nothing changes on the client.
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SameWalletAddressAndCard) {
+  // Create one profile and one card on the client.
+  AutofillProfile profile = test::GetServerProfile();
+  table()->SetServerProfiles({profile});
+  CreditCard card = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({card});
+
+  // Create the same profile and card on the server.
+  AutofillWalletSpecifics profile_specifics;
+  SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics);
+  AutofillWalletSpecifics card_specifics;
+  SetAutofillWalletSpecificsFromServerCard(card, &card_specifics);
+
+  StartSyncing({profile_specifics, card_specifics});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(EqualsSpecifics(profile_specifics),
+                                   EqualsSpecifics(card_specifics)));
+}
+
+// Tests that when there are multiple changes happening at the same time, the
+// data from the server is what the client ends up with,
+TEST_F(AutofillWalletSyncBridgeTest,
+       MergeSyncData_AddRemoveAndPreserveWalletAddressAndCard) {
+  // Create two profile and one card on the client.
+  AutofillProfile profile = test::GetServerProfile();
+  AutofillProfile profile2 = test::GetServerProfile2();
+  table()->SetServerProfiles({profile, profile2});
+  CreditCard card = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({card});
+
+  // Create one of the same profiles and a different card on the server.
+  AutofillWalletSpecifics profile_specifics;
+  SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics);
+  // The Amex card has different values for the relevant fields.
+  CreditCard card2 = test::GetMaskedServerCardAmex();
+  AutofillWalletSpecifics card_specifics;
+  SetAutofillWalletSpecificsFromServerCard(card, &card_specifics);
+
+  StartSyncing({profile_specifics, card_specifics});
+
+  // Make sure that the client only has the data from the server.
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(EqualsSpecifics(profile_specifics),
+                                   EqualsSpecifics(card_specifics)));
+}
+
+// Test that all field values for a address sent form the server are copied on
+// the address on the client.
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) {
+  // Create a profile to be synced from the server.
+  AutofillProfile profile = test::GetServerProfile();
+  AutofillWalletSpecifics profile_specifics;
+  SetAutofillWalletSpecificsFromServerProfile(profile, &profile_specifics);
+
+  StartSyncing({profile_specifics});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(EqualsSpecifics(profile_specifics)));
+
+  std::vector<std::unique_ptr<AutofillProfile>> profiles;
+  table()->GetServerProfiles(&profiles);
+  ASSERT_EQ(1U, profiles.size());
+
+  // Make sure that all the data was set properly.
+  EXPECT_EQ(profile.GetRawInfo(NAME_FULL), profiles[0]->GetRawInfo(NAME_FULL));
+  EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME),
+            profiles[0]->GetRawInfo(COMPANY_NAME));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_STATE),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_STATE));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_CITY),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_CITY));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_ZIP),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_ZIP));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_COUNTRY),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
+  EXPECT_EQ(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
+            profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  EXPECT_EQ(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_SORTING_CODE));
+  EXPECT_EQ(profile.language_code(), profiles[0]->language_code());
+
+  // Also make sure that those types are not empty, to exercice all the code
+  // paths.
+  EXPECT_FALSE(profile.GetRawInfo(NAME_FULL).empty());
+  EXPECT_FALSE(profile.GetRawInfo(COMPANY_NAME).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_STATE).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_CITY).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_ZIP).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty());
+  EXPECT_FALSE(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER).empty());
+  EXPECT_FALSE(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE).empty());
+  EXPECT_FALSE(profile.language_code().empty());
+}
+
+// Test that all field values for a card sent form the server are copied on the
+// card on the client.
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) {
+  // Create a card to be synced from the server.
+  CreditCard card = test::GetMaskedServerCard();
+  // Add this value type as it is not added by default but should be synced.
+  card.set_bank_name("The Bank");
+  AutofillWalletSpecifics card_specifics;
+  SetAutofillWalletSpecificsFromServerCard(card, &card_specifics);
+
+  StartSyncing({card_specifics});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(EqualsSpecifics(card_specifics)));
+
+  std::vector<std::unique_ptr<CreditCard>> cards;
+  table()->GetServerCreditCards(&cards);
+  ASSERT_EQ(1U, cards.size());
+
+  // Make sure that all the data was set properly.
+  EXPECT_EQ(card.network(), cards[0]->network());
+  EXPECT_EQ(card.LastFourDigits(), cards[0]->LastFourDigits());
+  EXPECT_EQ(card.expiration_month(), cards[0]->expiration_month());
+  EXPECT_EQ(card.expiration_year(), cards[0]->expiration_year());
+  EXPECT_EQ(card.billing_address_id(), cards[0]->billing_address_id());
+  EXPECT_EQ(card.card_type(), cards[0]->card_type());
+  EXPECT_EQ(card.bank_name(), cards[0]->bank_name());
+
+  // Also make sure that those types are not empty, to exercice all the code
+  // paths.
+  EXPECT_FALSE(card.network().empty());
+  EXPECT_FALSE(card.LastFourDigits().empty());
+  EXPECT_NE(0, card.expiration_month());
+  EXPECT_NE(0, card.expiration_year());
+  EXPECT_FALSE(card.billing_address_id().empty());
+  EXPECT_NE(CreditCard::CARD_TYPE_UNKNOWN, card.card_type());
+  EXPECT_FALSE(card.bank_name().empty());
+}
+
 }  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index bd3f5e6..27a429b9 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -33,7 +33,7 @@
   return reinterpret_cast<void*>(&user_data_key);
 }
 
-const char* CardNetworkFromWalletCardType(
+const char* CardNetworkFromAutofillWalletCardType(
     sync_pb::WalletMaskedCreditCard::WalletCardType type) {
   switch (type) {
     case sync_pb::WalletMaskedCreditCard::AMEX:
@@ -58,7 +58,7 @@
   }
 }
 
-CreditCard::CardType CardTypeFromWalletCardClass(
+CreditCard::CardType CardTypeFromAutofillWalletCardClass(
     sync_pb::WalletMaskedCreditCard::WalletCardClass card_class) {
   switch (card_class) {
     case sync_pb::WalletMaskedCreditCard::CREDIT:
@@ -72,7 +72,7 @@
   }
 }
 
-CreditCard::ServerStatus ServerToLocalStatus(
+CreditCard::ServerStatus ServerToLocalWalletCardStatus(
     sync_pb::WalletMaskedCreditCard::WalletCardStatus status) {
   switch (status) {
     case sync_pb::WalletMaskedCreditCard::VALID:
@@ -84,12 +84,14 @@
   }
 }
 
-CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) {
+CreditCard CardFromWalletCardSpecifics(
+    const sync_pb::WalletMaskedCreditCard& card) {
   CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id());
   result.SetNumber(base::UTF8ToUTF16(card.last_four()));
-  result.SetServerStatus(ServerToLocalStatus(card.status()));
-  result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type()));
-  result.set_card_type(CardTypeFromWalletCardClass(card.card_class()));
+  result.SetServerStatus(ServerToLocalWalletCardStatus(card.status()));
+  result.SetNetworkForMaskedCard(
+      CardNetworkFromAutofillWalletCardType(card.type()));
+  result.set_card_type(CardTypeFromAutofillWalletCardClass(card.card_class()));
   result.SetRawInfo(CREDIT_CARD_NAME_FULL,
                     base::UTF8ToUTF16(card.name_on_card()));
   result.SetExpirationMonth(card.exp_month());
@@ -99,7 +101,7 @@
   return result;
 }
 
-AutofillProfile ProfileFromSpecifics(
+AutofillProfile ProfileFromWalletCardSpecifics(
     const sync_pb::WalletPostalAddress& address) {
   AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string());
 
@@ -275,11 +277,11 @@
     switch (autofill_specifics.type()) {
       case sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD:
         wallet_cards->push_back(
-            CardFromSpecifics(autofill_specifics.masked_card()));
+            CardFromWalletCardSpecifics(autofill_specifics.masked_card()));
         break;
       case sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS:
         wallet_addresses->push_back(
-            ProfileFromSpecifics(autofill_specifics.address()));
+            ProfileFromWalletCardSpecifics(autofill_specifics.address()));
 
         // Map the sync billing address id to the profile's id.
         ids[autofill_specifics.address().id()] =
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 16b8176..c7a629f 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -26,6 +26,7 @@
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_metrics.h"
+#include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/base/cryptographer.h"
 #include "components/sync/base/passphrase_type.h"
 #include "components/sync/base/report_unrecoverable_error.h"
@@ -105,10 +106,9 @@
     sync_state = NOT_ALLOWED_BY_POLICY;
   } else if (disable_reasons &
              ProfileSyncService::DISABLE_REASON_PLATFORM_OVERRIDE) {
-    // This case means either a command-line flag or Android's "MasterSync"
-    // toggle. However, the latter is not plumbed into ProfileSyncService until
-    // after this method, so currently we only get here for the command-line
-    // case. See http://crbug.com/568771.
+    // This case means Android's "MasterSync" toggle. However, that is not
+    // plumbed into ProfileSyncService until after this method, so we never get
+    // here. See http://crbug.com/568771.
     sync_state = NOT_ALLOWED_BY_PLATFORM;
   } else if (disable_reasons & ProfileSyncService::DISABLE_REASON_USER_CHOICE) {
     if (first_setup_complete) {
@@ -1603,6 +1603,18 @@
         syncer::ConfigureContext::STORAGE_IN_MEMORY;
   }
   data_type_manager_->Configure(types, configure_context);
+
+  // Record in UMA whether we're configuring the full Sync feature or only the
+  // transport.
+  enum class ConfigureDataTypeManagerOption {
+    kFeature = 0,
+    kTransport = 1,
+    kMaxValue = kTransport
+  };
+  UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureDataTypeManagerOption",
+                            IsSyncFeatureEnabled()
+                                ? ConfigureDataTypeManagerOption::kFeature
+                                : ConfigureDataTypeManagerOption::kTransport);
 }
 
 syncer::UserShare* ProfileSyncService::GetUserShare() const {
@@ -1703,9 +1715,13 @@
                                           dtc_iter->second->state()));
       if (dtc_iter->second->state() !=
           syncer::DataTypeController::NOT_RUNNING) {
-        dtc_iter->second->GetStatusCounters(base::BindRepeating(
-            &ProfileSyncService::OnDatatypeStatusCounterUpdated,
-            base::Unretained(this)));
+        // We use BindToCurrentSequence() to make sure observers (i.e.
+        // |type_debug_info_observers_|) are not notified synchronously, which
+        // the UI code (chrome://sync-internals) doesn't handle well.
+        dtc_iter->second->GetStatusCounters(
+            BindToCurrentSequence(base::BindRepeating(
+                &ProfileSyncService::OnDatatypeStatusCounterUpdated,
+                base::Unretained(this))));
       }
     }
 
diff --git a/components/domain_reliability/service_unittest.cc b/components/domain_reliability/service_unittest.cc
index a115f15..877fc046 100644
--- a/components/domain_reliability/service_unittest.cc
+++ b/components/domain_reliability/service_unittest.cc
@@ -102,8 +102,8 @@
 
   int SubscribePermissionStatusChange(
       content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override {
     NOTIMPLEMENTED();
diff --git a/components/drive/job_scheduler.cc b/components/drive/job_scheduler.cc
index a88243e7..31523b7 100644
--- a/components/drive/job_scheduler.cc
+++ b/components/drive/job_scheduler.cc
@@ -156,8 +156,8 @@
 
 // Metadata jobs are cheap, so we run them concurrently. File jobs run serially.
 const int JobScheduler::kMaxJobCount[] = {
-  5,  // METADATA_QUEUE
-  1,  // FILE_QUEUE
+    20,  // METADATA_QUEUE
+    1,   // FILE_QUEUE
 };
 
 JobScheduler::JobEntry::JobEntry(JobType type)
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 15b3a14..296d41e 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -206,6 +206,7 @@
     "//components/encrypted_messages:encrypted_messages",
     "//components/variations",
     "//net",
+    "//services/network/public/cpp:cpp",
     "//third_party/metrics_proto",
     "//third_party/zlib/google:compression_utils",
     "//url",
@@ -378,6 +379,8 @@
     "//extensions/buildflags",
     "//mojo/public/cpp/bindings",
     "//net:test_support",
+    "//services/network:test_support",
+    "//services/network/public/cpp:cpp",
     "//services/service_manager/public/cpp",
     "//testing/gtest",
     "//third_party/zlib/google:compression_utils",
diff --git a/components/metrics/net/DEPS b/components/metrics/net/DEPS
index fcbd832..633e4afc 100644
--- a/components/metrics/net/DEPS
+++ b/components/metrics/net/DEPS
@@ -5,5 +5,7 @@
   "+components/encrypted_messages",
   "+components/variations",
   "+net",
+  "+services/network/public/cpp",
+  "+services/network/test",
   "+third_party/cros_system_api",
 ]
diff --git a/components/metrics/net/net_metrics_log_uploader.cc b/components/metrics/net/net_metrics_log_uploader.cc
index addad6b9..a213b92 100644
--- a/components/metrics/net/net_metrics_log_uploader.cc
+++ b/components/metrics/net/net_metrics_log_uploader.cc
@@ -15,6 +15,8 @@
 #include "net/base/url_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 #include "third_party/metrics_proto/reporting_info.pb.h"
 #include "url/gurl.h"
 
@@ -122,30 +124,43 @@
   return result;
 }
 
+void RecordUploadSizeForServiceTypeHistograms(
+    int64_t content_length,
+    metrics::MetricsLogUploader::MetricServiceType service_type) {
+  switch (service_type) {
+    case metrics::MetricsLogUploader::UMA:
+      UMA_HISTOGRAM_COUNTS_1M("UMA.LogUploader.UploadSize", content_length);
+      break;
+    case metrics::MetricsLogUploader::UKM:
+      UMA_HISTOGRAM_COUNTS_1M("UKM.LogUploader.UploadSize", content_length);
+      break;
+  }
+}
+
 }  // namespace
 
 namespace metrics {
 
 NetMetricsLogUploader::NetMetricsLogUploader(
-    net::URLRequestContextGetter* request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     base::StringPiece server_url,
     base::StringPiece mime_type,
     MetricsLogUploader::MetricServiceType service_type,
     const MetricsLogUploader::UploadCallback& on_upload_complete)
-    : request_context_getter_(request_context_getter),
+    : url_loader_factory_(std::move(url_loader_factory)),
       server_url_(server_url),
       mime_type_(mime_type.data(), mime_type.size()),
       service_type_(service_type),
       on_upload_complete_(on_upload_complete) {}
 
 NetMetricsLogUploader::NetMetricsLogUploader(
-    net::URLRequestContextGetter* request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     base::StringPiece server_url,
     base::StringPiece insecure_server_url,
     base::StringPiece mime_type,
     MetricsLogUploader::MetricServiceType service_type,
     const MetricsLogUploader::UploadCallback& on_upload_complete)
-    : request_context_getter_(request_context_getter),
+    : url_loader_factory_(std::move(url_loader_factory)),
       server_url_(server_url),
       insecure_server_url_(insecure_server_url),
       mime_type_(mime_type.data(), mime_type.size()),
@@ -179,88 +194,92 @@
     const ReportingInfo& reporting_info,
     const GURL& url) {
   DCHECK(!log_hash.empty());
-  current_fetch_ =
-      net::URLFetcher::Create(url, net::URLFetcher::POST, this,
-                              GetNetworkTrafficAnnotation(service_type_));
-  auto service = data_use_measurement::DataUseUserData::UMA;
 
-  switch (service_type_) {
-    case MetricsLogUploader::UMA:
-      service = data_use_measurement::DataUseUserData::UMA;
-      break;
-    case MetricsLogUploader::UKM:
-      service = data_use_measurement::DataUseUserData::UKM;
-      break;
-  }
-  data_use_measurement::DataUseUserData::AttachToFetcher(current_fetch_.get(),
-                                                         service);
-  current_fetch_->SetRequestContext(request_context_getter_);
+  // TODO(crbug.com/808498): Restore the data use measurement when bug is fixed.
+
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = url;
+  // Drop cookies and auth data.
+  resource_request->load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA |
+                                 net::LOAD_DO_NOT_SEND_COOKIES |
+                                 net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->method = "POST";
+
   std::string reporting_info_string = SerializeReportingInfo(reporting_info);
   // If we are not using HTTPS for this upload, encrypt it. We do not encrypt
   // requests to localhost to allow testing with a local collector that doesn't
   // have decryption enabled.
-  if (!url.SchemeIs(url::kHttpsScheme) && !net::IsLocalhost(url)) {
-    std::string encrypted_message;
-    if (!EncryptString(compressed_log_data, &encrypted_message)) {
-      current_fetch_.reset();
-      on_upload_complete_.Run(0, net::ERR_FAILED, false);
-      return;
-    }
-    current_fetch_->SetUploadData(mime_type_, encrypted_message);
-
+  bool should_encrypt =
+      !url.SchemeIs(url::kHttpsScheme) && !net::IsLocalhost(url);
+  if (should_encrypt) {
     std::string encrypted_hash;
     std::string base64_encoded_hash;
     if (!EncryptString(log_hash, &encrypted_hash)) {
-      current_fetch_.reset();
       on_upload_complete_.Run(0, net::ERR_FAILED, false);
       return;
     }
     base::Base64Encode(encrypted_hash, &base64_encoded_hash);
-    current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " +
-                                          base64_encoded_hash);
+    resource_request->headers.SetHeader("X-Chrome-UMA-Log-SHA1",
+                                        base64_encoded_hash);
 
     std::string encrypted_reporting_info;
     std::string base64_reporting_info;
     if (!EncryptString(reporting_info_string, &encrypted_reporting_info)) {
-      current_fetch_.reset();
       on_upload_complete_.Run(0, net::ERR_FAILED, false);
       return;
     }
     base::Base64Encode(encrypted_reporting_info, &base64_reporting_info);
-    current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-ReportingInfo: " +
-                                          base64_reporting_info);
+    resource_request->headers.SetHeader("X-Chrome-UMA-ReportingInfo",
+                                        base64_reporting_info);
   } else {
-    current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + log_hash);
-    current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-ReportingInfo:" +
-                                          reporting_info_string);
-    current_fetch_->SetUploadData(mime_type_, compressed_log_data);
+    resource_request->headers.SetHeader("X-Chrome-UMA-Log-SHA1", log_hash);
+    resource_request->headers.SetHeader("X-Chrome-UMA-ReportingInfo",
+                                        reporting_info_string);
     // Tell the server that we're uploading gzipped protobufs only if we are not
     // encrypting, since encrypted messages have to be decrypted server side
     // after decryption, not before.
-    current_fetch_->AddExtraRequestHeader("content-encoding: gzip");
+    resource_request->headers.SetHeader("content-encoding", "gzip");
   }
-  // Drop cookies and auth data.
-  current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
-                               net::LOAD_DO_NOT_SEND_AUTH_DATA |
-                               net::LOAD_DO_NOT_SEND_COOKIES);
-  current_fetch_->Start();
+
+  url_loader_ = network::SimpleURLLoader::Create(
+      std::move(resource_request), GetNetworkTrafficAnnotation(service_type_));
+
+  if (should_encrypt) {
+    std::string encrypted_message;
+    if (!EncryptString(compressed_log_data, &encrypted_message)) {
+      url_loader_.reset();
+      on_upload_complete_.Run(0, net::ERR_FAILED, false);
+      return;
+    }
+    url_loader_->AttachStringForUpload(encrypted_message, mime_type_);
+    RecordUploadSizeForServiceTypeHistograms(encrypted_message.size(),
+                                             service_type_);
+  } else {
+    url_loader_->AttachStringForUpload(compressed_log_data, mime_type_);
+    RecordUploadSizeForServiceTypeHistograms(compressed_log_data.size(),
+                                             service_type_);
+  }
+
+  // It's safe to use |base::Unretained(this)| here, because |this| owns
+  // the |url_loader_|, and the callback will be cancelled if the |url_loader_|
+  // is destroyed.
+  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_.get(),
+      base::BindOnce(&NetMetricsLogUploader::OnURLLoadComplete,
+                     base::Unretained(this)));
 }
 
-void NetMetricsLogUploader::OnURLFetchComplete(const net::URLFetcher* source) {
-  // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
-  // Note however that |source| is aliased to the fetcher, so we should be
-  // careful not to delete it too early.
-  DCHECK_EQ(current_fetch_.get(), source);
-  int response_code = source->GetResponseCode();
-  if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID)
-    response_code = -1;
-  int error_code = 0;
-  const net::URLRequestStatus& request_status = source->GetStatus();
-  if (request_status.status() != net::URLRequestStatus::SUCCESS) {
-    error_code = request_status.error();
-  }
-  bool was_https = source->GetURL().SchemeIs(url::kHttpsScheme);
-  current_fetch_.reset();
+// The callback is only invoked if |url_loader_| it was bound against is alive.
+void NetMetricsLogUploader::OnURLLoadComplete(
+    std::unique_ptr<std::string> response_body) {
+  int response_code = -1;
+  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers)
+    response_code = url_loader_->ResponseInfo()->headers->response_code();
+
+  int error_code = url_loader_->NetError();
+
+  bool was_https = url_loader_->GetFinalURL().SchemeIs(url::kHttpsScheme);
+  url_loader_.reset();
   on_upload_complete_.Run(response_code, error_code, was_https);
 }
 
diff --git a/components/metrics/net/net_metrics_log_uploader.h b/components/metrics/net/net_metrics_log_uploader.h
index 5c4045bd..99fce26 100644
--- a/components/metrics/net/net_metrics_log_uploader.h
+++ b/components/metrics/net/net_metrics_log_uploader.h
@@ -11,29 +11,25 @@
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "components/metrics/metrics_log_uploader.h"
-#include "net/url_request/url_fetcher_delegate.h"
 #include "third_party/metrics_proto/reporting_info.pb.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
-}
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
 
 namespace metrics {
 
 // Implementation of MetricsLogUploader using the Chrome network stack.
-class NetMetricsLogUploader : public MetricsLogUploader,
-                              public net::URLFetcherDelegate {
+class NetMetricsLogUploader : public MetricsLogUploader {
  public:
   // Constructs a NetMetricsLogUploader which uploads data to |server_url| with
   // the specified |mime_type|. The |service_type| marks which service the
   // data usage should be attributed to. The |on_upload_complete| callback will
   // be called with the HTTP response code of the upload or with -1 on an error.
-  // The caller must ensure that |request_context_getter| remains valid for the
-  // lifetime of this class.
   NetMetricsLogUploader(
-      net::URLRequestContextGetter* request_context_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       base::StringPiece server_url,
       base::StringPiece mime_type,
       MetricsLogUploader::MetricServiceType service_type,
@@ -43,7 +39,7 @@
   // |insecure_server_url|. That URL is used as a fallback if a connection
   // to |server_url| fails, requests are encrypted when sent to an HTTP URL.
   NetMetricsLogUploader(
-      net::URLRequestContextGetter* request_context_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       base::StringPiece server_url,
       base::StringPiece insecure_server_url,
       base::StringPiece mime_type,
@@ -65,15 +61,14 @@
                       const ReportingInfo& reporting_info,
                       const GURL& url);
 
-  // net::URLFetcherDelegate:
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  void OnURLLoadComplete(std::unique_ptr<std::string> response_body);
 
   // Encrypts a |plaintext| string, using the encrypted_messages component,
   // returns |encrypted| which is a serialized EncryptedMessage object.
   bool EncryptString(const std::string& plaintext, std::string* encrypted);
 
-  // The request context for fetches done using the network stack.
-  net::URLRequestContextGetter* const request_context_getter_;
+  // The URLLoader factory for loads done using the network stack.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   const GURL server_url_;
   const GURL insecure_server_url_;
@@ -81,7 +76,7 @@
   const MetricsLogUploader ::MetricServiceType service_type_;
   const MetricsLogUploader::UploadCallback on_upload_complete_;
   // The outstanding transmission appears as a URL Fetch operation.
-  std::unique_ptr<net::URLFetcher> current_fetch_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
 
   DISALLOW_COPY_AND_ASSIGN(NetMetricsLogUploader);
 };
diff --git a/components/metrics/net/net_metrics_log_uploader_unittest.cc b/components/metrics/net/net_metrics_log_uploader_unittest.cc
index 76652ec..f6aecdc9 100644
--- a/components/metrics/net/net_metrics_log_uploader_unittest.cc
+++ b/components/metrics/net/net_metrics_log_uploader_unittest.cc
@@ -7,8 +7,14 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/encrypted_messages/encrypted_message.pb.h"
 #include "net/url_request/test_url_fetcher_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/reporting_info.pb.h"
 #include "third_party/zlib/google/compression_utils.h"
@@ -18,14 +24,25 @@
 
 class NetMetricsLogUploaderTest : public testing::Test {
  public:
-  NetMetricsLogUploaderTest() : on_upload_complete_count_(0) {
+  NetMetricsLogUploaderTest()
+      : on_upload_complete_count_(0),
+        test_shared_url_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {
+    test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+        [&](const network::ResourceRequest& request) {
+          upload_data_ = network::GetUploadData(request);
+          headers_ = request.headers;
+          loop_.Quit();
+        }));
   }
 
   void CreateAndOnUploadCompleteReuseUploader() {
     ReportingInfo reporting_info;
     reporting_info.set_attempt_count(10);
     uploader_.reset(new NetMetricsLogUploader(
-        nullptr, "https://dummy_server", "dummy_mime", MetricsLogUploader::UMA,
+        test_shared_url_loader_factory_, "https://dummy_server", "dummy_mime",
+        MetricsLogUploader::UMA,
         base::Bind(&NetMetricsLogUploaderTest::OnUploadCompleteReuseUploader,
                    base::Unretained(this))));
     uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash",
@@ -35,7 +52,8 @@
   void CreateUploaderAndUploadToSecureURL(const std::string& url) {
     ReportingInfo dummy_reporting_info;
     uploader_.reset(new NetMetricsLogUploader(
-        nullptr, url, "dummy_mime", MetricsLogUploader::UMA,
+        test_shared_url_loader_factory_, url, "dummy_mime",
+        MetricsLogUploader::UMA,
         base::Bind(&NetMetricsLogUploaderTest::DummyOnUploadComplete,
                    base::Unretained(this))));
     uploader_->UploadLog("dummy_data", "dummy_hash", dummy_reporting_info);
@@ -44,8 +62,8 @@
   void CreateUploaderAndUploadToInsecureURL() {
     ReportingInfo dummy_reporting_info;
     uploader_.reset(new NetMetricsLogUploader(
-        nullptr, "http://dummy_insecure_server", "dummy_mime",
-        MetricsLogUploader::UMA,
+        test_shared_url_loader_factory_, "http://dummy_insecure_server",
+        "dummy_mime", MetricsLogUploader::UMA,
         base::Bind(&NetMetricsLogUploaderTest::DummyOnUploadComplete,
                    base::Unretained(this))));
     std::string compressed_message;
@@ -71,20 +89,48 @@
     }
   }
 
+  network::TestURLLoaderFactory::PendingRequest* GetPendingRequest(
+      size_t index) {
+    if (index >= test_url_loader_factory_.pending_requests()->size())
+      return nullptr;
+    auto* request = &(*test_url_loader_factory_.pending_requests())[index];
+    DCHECK(request);
+    return request;
+  }
+
   int on_upload_complete_count() const {
     return on_upload_complete_count_;
   }
 
+  network::TestURLLoaderFactory* test_url_loader_factory() {
+    return &test_url_loader_factory_;
+  }
+
+  const net::HttpRequestHeaders& last_request_headers() { return headers_; }
+
+  const std::string& last_upload_data() { return upload_data_; }
+
+  void WaitForRequest() { loop_.Run(); }
+
  private:
   std::unique_ptr<NetMetricsLogUploader> uploader_;
   int on_upload_complete_count_;
+
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory>
+      test_shared_url_loader_factory_;
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  base::RunLoop loop_;
+  std::string upload_data_;
+  net::HttpRequestHeaders headers_;
+
   DISALLOW_COPY_AND_ASSIGN(NetMetricsLogUploaderTest);
 };
 
-void CheckReportingInfoHeader(net::TestURLFetcher* fetcher,
+void CheckReportingInfoHeader(net::HttpRequestHeaders headers,
                               int expected_attempt_count) {
-  net::HttpRequestHeaders headers;
-  fetcher->GetExtraRequestHeaders(&headers);
   std::string reporting_info_base64;
   EXPECT_TRUE(
       headers.GetHeader("X-Chrome-UMA-ReportingInfo", &reporting_info_base64));
@@ -97,18 +143,18 @@
 }
 
 TEST_F(NetMetricsLogUploaderTest, OnUploadCompleteReuseUploader) {
-  net::TestURLFetcherFactory factory;
   CreateAndOnUploadCompleteReuseUploader();
+  WaitForRequest();
 
   // Mimic the initial fetcher callback.
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  CheckReportingInfoHeader(fetcher, 10);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  CheckReportingInfoHeader(last_request_headers(), 10);
+  test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList(
+      GetPendingRequest(0), "");
 
   // Mimic the second fetcher callback.
-  fetcher = factory.GetFetcherByID(0);
-  CheckReportingInfoHeader(fetcher, 20);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  CheckReportingInfoHeader(last_request_headers(), 20);
+  test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList(
+      GetPendingRequest(1), "");
 
   EXPECT_EQ(on_upload_complete_count(), 2);
 }
@@ -116,29 +162,26 @@
 // Test that attempting to upload to an HTTP URL results in an encrypted
 // message.
 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPIsEncrypted) {
-  net::TestURLFetcherFactory factory;
   CreateUploaderAndUploadToInsecureURL();
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+  WaitForRequest();
   encrypted_messages::EncryptedMessage message;
-  EXPECT_TRUE(message.ParseFromString(fetcher->upload_data()));
+  EXPECT_TRUE(message.ParseFromString(last_upload_data()));
 }
 
 // Test that attempting to upload to an HTTPS URL results in an unencrypted
 // message.
 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPSIsNotEncrypted) {
-  net::TestURLFetcherFactory factory;
   CreateUploaderAndUploadToSecureURL("https://dummy_secure_server");
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_EQ(fetcher->upload_data(), "dummy_data");
+  WaitForRequest();
+  EXPECT_EQ(last_upload_data(), "dummy_data");
 }
 
 // Test that attempting to upload to localhost over http results in an
 // unencrypted message.
 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPLocalhostIsNotEncrypted) {
-  net::TestURLFetcherFactory factory;
   CreateUploaderAndUploadToSecureURL("http://localhost");
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_EQ(fetcher->upload_data(), "dummy_data");
+  WaitForRequest();
+  EXPECT_EQ(last_upload_data(), "dummy_data");
 }
 
 }  // namespace metrics
diff --git a/components/omnibox/browser/document_suggestions_service.cc b/components/omnibox/browser/document_suggestions_service.cc
index 7906a090..4b74167fd 100644
--- a/components/omnibox/browser/document_suggestions_service.cc
+++ b/components/omnibox/browser/document_suggestions_service.cc
@@ -74,8 +74,10 @@
     const TemplateURLService* template_url_service,
     StartCallback start_callback,
     CompletionCallback completion_callback) {
-  std::string endpoint = variations::GetVariationParamValueByFeature(
-      omnibox::kDocumentProvider, "Endpoint");
+  std::string endpoint = base::GetFieldTrialParamValueByFeature(
+      omnibox::kDocumentProvider, "DocumentProviderEndpoint");
+  if (endpoint.empty())
+    endpoint = "https://cloudsearch.googleapis.com/v1/query/search";
   const GURL suggest_url = GURL(endpoint);
   DCHECK(suggest_url.is_valid());
 
@@ -111,16 +113,9 @@
   // TODO(https://crbug.com/808498) re-add data use measurement once
   // SimpleURLLoader supports it.
   // We should attach data_use_measurement::DataUseUserData::OMNIBOX.
-  StartDownloadAndTransferLoader(std::move(request), std::string(),
-                                 traffic_annotation, std::move(start_callback),
-                                 std::move(completion_callback));
-
-  // TODO(skare): Include code to catch token fetch in-progress; otherwise
-  // we'll lose one set of results.
 
   // Create and fetch an OAuth2 token.
-  std::string scope = base::GetFieldTrialParamValueByFeature(
-      omnibox::kDocumentProvider, "OAuth2Scope");
+  std::string scope = "https://www.googleapis.com/auth/cloud_search.query";
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(scope);
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 081bedc..dbc6518 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -93,16 +93,8 @@
     LOG(ERROR) << "SSL certificate is not valid";
 
   if (!allowed_origin || invalid_ssl) {
-    // Don't show UI. Resolve .canMakepayment() with "false". Reject .show()
-    // with "NotSupportedError".
-    spec_ = std::make_unique<PaymentRequestSpec>(
-        mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
-        std::vector<mojom::PaymentMethodDataPtr>(), this,
-        delegate_->GetApplicationLocale());
-    state_ = std::make_unique<PaymentRequestState>(
-        web_contents_, top_level_origin_, frame_origin_, spec_.get(), this,
-        delegate_->GetApplicationLocale(), delegate_->GetPersonalDataManager(),
-        delegate_.get(), &journey_logger_);
+    // Intentionally don't set |spec_| and |state_|. Don't show UI. Resolve
+    // .canMakepayment() with "false". Reject .show() with "NotSupportedError".
     return;
   }
 
@@ -178,10 +170,16 @@
     return;
   }
 
+  if (!state_) {
+    // SSL is not valid.
+    AreRequestedMethodsSupportedCallback(false);
+    return;
+  }
+
   is_show_user_gesture_ = is_user_gesture;
 
-  // TODO(crbug.com/783811): Display a spinner when checking whether
-  // the methods are supported asynchronously for better user experience.
+  display_handle_->Show(this);
+
   state_->AreRequestedMethodsSupported(
       base::BindOnce(&PaymentRequest::AreRequestedMethodsSupportedCallback,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -205,10 +203,8 @@
 void PaymentRequest::AreRequestedMethodsSupportedCallback(
     bool methods_supported) {
   if (methods_supported) {
-    journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
-
-    DCHECK(display_handle_);
-    display_handle_->Show(this);
+    if (SatisfiesSkipUIConstraints())
+      Pay();
   } else {
     journey_logger_.SetNotShown(
         JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
@@ -285,10 +281,11 @@
   if (observer_for_testing_)
     observer_for_testing_->OnCanMakePaymentCalled();
 
-  if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled)) {
+  if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled) ||
+      !state_) {
     CanMakePaymentCallback(/*can_make_payment=*/false);
   } else {
-    state()->CanMakePayment(
+    state_->CanMakePayment(
         base::BindOnce(&PaymentRequest::CanMakePaymentCallback,
                        weak_ptr_factory_.GetWeakPtr()));
   }
@@ -389,6 +386,10 @@
   display_handle_.reset();
 }
 
+void PaymentRequest::RecordDialogShownEventInJourneyLogger() {
+  journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
+}
+
 bool PaymentRequest::IsIncognito() const {
   return delegate_->IsIncognito();
 }
@@ -415,10 +416,10 @@
 }
 
 void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
-  if (CanMakePaymentQueryFactory::GetInstance()
-          ->GetForContext(web_contents_->GetBrowserContext())
-          ->CanQuery(top_level_origin_, frame_origin_,
-                     spec()->stringified_method_data())) {
+  if (!spec_ || CanMakePaymentQueryFactory::GetInstance()
+                    ->GetForContext(web_contents_->GetBrowserContext())
+                    ->CanQuery(top_level_origin_, frame_origin_,
+                               spec_->stringified_method_data())) {
     RespondToCanMakePaymentQuery(can_make_payment, false);
   } else if (OriginSecurityChecker::IsOriginLocalhostOrFile(frame_origin_)) {
     RespondToCanMakePaymentQuery(can_make_payment, true);
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 42c6e25d..25b15e9a7 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -102,6 +102,9 @@
   // Hide this Payment Request if it's already showing.
   void HideIfNecessary();
 
+  // Record the "dialog shown" event in the journey logger.
+  void RecordDialogShownEventInJourneyLogger();
+
   bool IsIncognito() const;
 
   // Returns true if this payment request supports skipping the Payment Sheet.
diff --git a/components/payments/content/payment_request_display_manager.h b/components/payments/content/payment_request_display_manager.h
index 222556b..23e35d9 100644
--- a/components/payments/content/payment_request_display_manager.h
+++ b/components/payments/content/payment_request_display_manager.h
@@ -31,8 +31,8 @@
  public:
   class DisplayHandle {
    public:
-    explicit DisplayHandle(PaymentRequestDisplayManager* display_manager,
-                           ContentPaymentRequestDelegate* delegate);
+    DisplayHandle(PaymentRequestDisplayManager* display_manager,
+                  ContentPaymentRequestDelegate* delegate);
     ~DisplayHandle();
     void Show(PaymentRequest* request);
     // Attempt to display |url| inside the Payment Request dialog and run
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 3cfe66c..766789d 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -46,6 +46,8 @@
       delegate_(delegate),
       personal_data_manager_(personal_data_manager),
       journey_logger_(journey_logger),
+      are_requested_methods_supported_(
+          !spec_->supported_card_networks().empty()),
       selected_shipping_profile_(nullptr),
       selected_shipping_option_error_profile_(nullptr),
       selected_contact_profile_(nullptr),
@@ -140,6 +142,7 @@
   SetDefaultProfileSelections();
 
   get_all_instruments_finished_ = true;
+  are_requested_methods_supported_ |= !available_instruments_.empty();
   NotifyOnGetAllPaymentInstrumentsFinished();
 
   // Fullfill the pending CanMakePayment call.
@@ -208,8 +211,7 @@
     StatusCallback callback) {
   DCHECK(get_all_instruments_finished_);
 
-  std::move(callback).Run(!spec_->supported_card_networks().empty() ||
-                          !available_instruments_.empty());
+  std::move(callback).Run(are_requested_methods_supported_);
 }
 
 std::string PaymentRequestState::GetAuthenticatedEmail() const {
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index 47bab37..10f4d9b 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -182,6 +182,13 @@
     return get_all_instruments_finished_;
   }
 
+  // Returns true after is_get_all_instruments_finished() is true and supported
+  // payment method are found. Should not be called before
+  // is_get_all_instruments_finished() is true.
+  bool are_requested_methods_supported() const {
+    return are_requested_methods_supported_;
+  }
+
   const std::string& GetApplicationLocale();
   autofill::PersonalDataManager* GetPersonalDataManager();
   autofill::RegionDataLoader* GetRegionDataLoader();
@@ -270,6 +277,7 @@
 
   StatusCallback can_make_payment_callback_;
   StatusCallback are_requested_methods_supported_callback_;
+  bool are_requested_methods_supported_;
 
   autofill::AutofillProfile* selected_shipping_profile_;
   autofill::AutofillProfile* selected_shipping_option_error_profile_;
diff --git a/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc b/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc
index cc68640..e9c32c42 100644
--- a/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc
+++ b/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc
@@ -52,12 +52,13 @@
     return is_ready_;
   }
 
-  void OnCompositeToPdfCallback(mojom::PdfCompositor::Status status,
-                                base::ReadOnlySharedMemoryRegion region) {
+  static void OnCompositeToPdfCallback(
+      mojom::PdfCompositor::Status status,
+      base::ReadOnlySharedMemoryRegion region) {
     // A stub for testing, no implementation.
   }
 
- protected:
+ private:
   base::test::ScopedTaskEnvironment task_environment_;
   std::unique_ptr<base::RunLoop> run_loop_;
   bool is_ready_;
@@ -89,44 +90,35 @@
 
   // Frame 1 contains content 3 which corresponds to frame 2.
   // Frame 1 should be ready as frame 2 is ready.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[3u] = 2u;
+  ContentToFrameMap subframe_content_map = {{3u, 2u}};
   base::flat_set<uint64_t> pending_subframes;
-  bool is_ready = impl.IsReadyToComposite(1u, std::move(subframe_content_map),
-                                          &pending_subframes);
+  bool is_ready =
+      impl.IsReadyToComposite(1u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 
   // If another page of frame 1 needs content 2 which corresponds to frame 3.
   // This page is ready since frame 3 was painted also.
-  subframe_content_map.clear();
-  subframe_content_map[2u] = 3u;
-  is_ready = impl.IsReadyToComposite(1u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{2u, 3u}};
+  is_ready =
+      impl.IsReadyToComposite(1u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 
   // Frame 1 with content 1, 2 and 3 should not be ready since content 1's
   // content in frame 4 is not painted yet.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 4u;
-  subframe_content_map[2u] = 3u;
-  subframe_content_map[3u] = 2u;
-  is_ready = impl.IsReadyToComposite(1u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{1u, 4u}, {2u, 3u}, {3u, 2u}};
+  is_ready =
+      impl.IsReadyToComposite(1u, subframe_content_map, &pending_subframes);
   EXPECT_FALSE(is_ready);
   ASSERT_EQ(pending_subframes.size(), 1u);
   EXPECT_EQ(*pending_subframes.begin(), 4u);
 
   // Add content of frame 4. Now it is ready for composition.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 4u;
-  subframe_content_map[2u] = 3u;
-  subframe_content_map[3u] = 2u;
   impl.AddSubframeContent(4u, mojo::SharedBufferHandle::Create(10),
                           ContentToFrameMap());
-  is_ready = impl.IsReadyToComposite(1u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  is_ready =
+      impl.IsReadyToComposite(1u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 }
@@ -134,28 +126,25 @@
 TEST_F(PdfCompositorImplTest, MultiLayerDependency) {
   PdfCompositorImpl impl("unittest", nullptr);
   // Frame 3 has content 1 which refers to subframe 1.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[1u] = 1u;
+  ContentToFrameMap subframe_content_map = {{1u, 1u}};
   impl.AddSubframeContent(3u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          subframe_content_map);
 
   // Frame 5 has content 3 which refers to subframe 3.
   // Although frame 3's content is added, its subframe 1's content is not added.
   // So frame 5 is not ready.
-  subframe_content_map.clear();
-  subframe_content_map[3u] = 3u;
+  subframe_content_map = {{3u, 3u}};
   base::flat_set<uint64_t> pending_subframes;
-  bool is_ready = impl.IsReadyToComposite(5u, std::move(subframe_content_map),
-                                          &pending_subframes);
+  bool is_ready =
+      impl.IsReadyToComposite(5u, subframe_content_map, &pending_subframes);
   EXPECT_FALSE(is_ready);
   ASSERT_EQ(pending_subframes.size(), 1u);
   EXPECT_EQ(*pending_subframes.begin(), 1u);
 
   // Frame 6 is not ready either since it needs frame 5 to be ready.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 5u;
-  is_ready = impl.IsReadyToComposite(6u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{1u, 5u}};
+  is_ready =
+      impl.IsReadyToComposite(6u, subframe_content_map, &pending_subframes);
   EXPECT_FALSE(is_ready);
   ASSERT_EQ(pending_subframes.size(), 1u);
   EXPECT_EQ(*pending_subframes.begin(), 5u);
@@ -163,24 +152,20 @@
   // When frame 1's content is added, frame 5 is ready.
   impl.AddSubframeContent(1u, mojo::SharedBufferHandle::Create(10),
                           ContentToFrameMap());
-  subframe_content_map.clear();
-  subframe_content_map[3u] = 3u;
-  is_ready = impl.IsReadyToComposite(5u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{3u, 3u}};
+  is_ready =
+      impl.IsReadyToComposite(5u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 
   // Add frame 5's content.
-  subframe_content_map.clear();
-  subframe_content_map[3u] = 3u;
   impl.AddSubframeContent(5u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          subframe_content_map);
 
   // Frame 6 is ready too.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 5u;
-  is_ready = impl.IsReadyToComposite(6u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{1u, 5u}};
+  is_ready =
+      impl.IsReadyToComposite(6u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 }
@@ -189,36 +174,31 @@
   PdfCompositorImpl impl("unittest", nullptr);
   // Frame 3 has content 1, which refers to frame 1.
   // Frame 1 has content 3, which refers to frame 3.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[3u] = 3u;
+  ContentToFrameMap subframe_content_map = {{3u, 3u}};
   impl.AddSubframeContent(1u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          subframe_content_map);
 
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 1u;
+  subframe_content_map = {{1u, 1u}};
   impl.AddSubframeContent(3u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          subframe_content_map);
 
   // Both frame 1 and 3 are painted, frame 5 should be ready.
   base::flat_set<uint64_t> pending_subframes;
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 3u;
-  bool is_ready = impl.IsReadyToComposite(5u, std::move(subframe_content_map),
-                                          &pending_subframes);
+  subframe_content_map = {{1u, 3u}};
+  bool is_ready =
+      impl.IsReadyToComposite(5u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 
   // Frame 6 has content 7, which refers to frame 7.
-  subframe_content_map.clear();
-  subframe_content_map[7u] = 7u;
+  subframe_content_map = {{7u, 7u}};
   impl.AddSubframeContent(6, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          subframe_content_map);
   // Frame 7 should be ready since frame 6's own content is added and it only
   // depends on frame 7.
-  subframe_content_map.clear();
-  subframe_content_map[6u] = 6u;
-  is_ready = impl.IsReadyToComposite(7u, std::move(subframe_content_map),
-                                     &pending_subframes);
+  subframe_content_map = {{6u, 6u}};
+  is_ready =
+      impl.IsReadyToComposite(7u, subframe_content_map, &pending_subframes);
   EXPECT_TRUE(is_ready);
   EXPECT_TRUE(pending_subframes.empty());
 }
@@ -227,71 +207,51 @@
   MockPdfCompositorImpl impl;
   // Page 0 with frame 3 has content 1, which refers to frame 8.
   // When the content is not available, the request is not fulfilled.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[1u] = 8u;
+  const ContentToFrameMap subframe_content_map = {{1u, 8u}};
   EXPECT_CALL(impl, OnFulfillRequest(testing::_, testing::_)).Times(0);
   impl.CompositePageToPdf(
-      3u, 0, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, 0, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
   testing::Mock::VerifyAndClearExpectations(&impl);
 
   // When frame 8's content is ready, the previous request should be fulfilled.
   EXPECT_CALL(impl, OnFulfillRequest(3u, 0)).Times(1);
   impl.AddSubframeContent(8u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          ContentToFrameMap());
   testing::Mock::VerifyAndClearExpectations(&impl);
 
   // The following requests which only depends on frame 8 should be
   // immediately fulfilled.
   EXPECT_CALL(impl, OnFulfillRequest(3u, 1)).Times(1);
   EXPECT_CALL(impl, OnFulfillRequest(3u, -1)).Times(1);
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 8u;
   impl.CompositePageToPdf(
-      3u, 1, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, 1, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
 
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 8u;
   impl.CompositeDocumentToPdf(
-      3u, mojo::SharedBufferHandle::Create(10), std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
 }
 
 TEST_F(PdfCompositorImplTest, MultiRequestsOrder) {
   MockPdfCompositorImpl impl;
-  // Page 0 with frame  3 has content 1, which refers to frame 8.
+  // Page 0 with frame 3 has content 1, which refers to frame 8.
   // When the content is not available, the request is not fulfilled.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[1u] = 8u;
+  const ContentToFrameMap subframe_content_map = {{1u, 8u}};
   EXPECT_CALL(impl, OnFulfillRequest(testing::_, testing::_)).Times(0);
   impl.CompositePageToPdf(
-      3u, 0, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, 0, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
 
   // The following requests which only depends on frame 8 should be
   // immediately fulfilled.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 8u;
   impl.CompositePageToPdf(
-      3u, 1, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, 1, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
 
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 8u;
   impl.CompositeDocumentToPdf(
-      3u, mojo::SharedBufferHandle::Create(10), std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
   testing::Mock::VerifyAndClearExpectations(&impl);
 
   // When frame 8's content is ready, the previous request should be
@@ -299,9 +259,8 @@
   EXPECT_CALL(impl, OnFulfillRequest(3u, 0)).Times(1);
   EXPECT_CALL(impl, OnFulfillRequest(3u, 1)).Times(1);
   EXPECT_CALL(impl, OnFulfillRequest(3u, -1)).Times(1);
-  subframe_content_map.clear();
   impl.AddSubframeContent(8u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          ContentToFrameMap());
 }
 
 TEST_F(PdfCompositorImplTest, MultiRequestsDepOrder) {
@@ -310,24 +269,18 @@
   // 2. When the content is not available, the request is not
   // fulfilled.
   EXPECT_CALL(impl, OnFulfillRequest(testing::_, testing::_)).Times(0);
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[1u] = 2u;
+  ContentToFrameMap subframe_content_map = {{1u, 2u}};
   impl.CompositePageToPdf(
-      1u, 0, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      1u, 0, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
 
   // Page 1 with frame 1 has content 1, which refers to frame
   // 3. When the content is not available, the request is not
   // fulfilled either.
-  subframe_content_map.clear();
-  subframe_content_map[1u] = 3u;
+  subframe_content_map = {{1u, 3u}};
   impl.CompositePageToPdf(
-      1u, 1, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      1u, 1, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
   testing::Mock::VerifyAndClearExpectations(&impl);
 
   // When frame 3 and 2 become available, the pending requests should be
@@ -335,25 +288,21 @@
   testing::Sequence order;
   EXPECT_CALL(impl, OnFulfillRequest(1, 1)).Times(1).InSequence(order);
   EXPECT_CALL(impl, OnFulfillRequest(1, 0)).Times(1).InSequence(order);
-  subframe_content_map.clear();
   impl.AddSubframeContent(3u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          ContentToFrameMap());
   impl.AddSubframeContent(2u, mojo::SharedBufferHandle::Create(10),
-                          std::move(subframe_content_map));
+                          ContentToFrameMap());
 }
 
 TEST_F(PdfCompositorImplTest, NotifyUnavailableSubframe) {
   MockPdfCompositorImpl impl;
   // Page 0 with frame 3 has content 1, which refers to frame 8.
   // When the content is not available, the request is not fulfilled.
-  ContentToFrameMap subframe_content_map;
-  subframe_content_map[1u] = 8u;
+  const ContentToFrameMap subframe_content_map = {{1u, 8u}};
   EXPECT_CALL(impl, OnFulfillRequest(testing::_, testing::_)).Times(0);
   impl.CompositePageToPdf(
-      3u, 0, mojo::SharedBufferHandle::Create(10),
-      std::move(subframe_content_map),
-      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback,
-                     base::Unretained(this)));
+      3u, 0, mojo::SharedBufferHandle::Create(10), subframe_content_map,
+      base::BindOnce(&PdfCompositorImplTest::OnCompositeToPdfCallback));
   testing::Mock::VerifyAndClearExpectations(&impl);
 
   // Notifies that frame 8's unavailable, the previous request should be
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index e3585ea..27934aaf 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -929,7 +929,7 @@
     "//chrome/test/data/sync/",
     "//net/tools/testserver/",
     "//third_party/pyftpdlib/",
-    "//third_party/pywebsocket/",
+    "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
     "$root_out_dir/pyproto/google/",
   ]
diff --git a/components/sync/engine_impl/non_blocking_type_commit_contribution.cc b/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
index eb61e14..68358c25 100644
--- a/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
+++ b/components/sync/engine_impl/non_blocking_type_commit_contribution.cc
@@ -173,7 +173,10 @@
     sync_pb::SyncEntity* commit_proto) {
   const EntityData& entity_data = commit_entity.entity.value();
   commit_proto->set_id_string(entity_data.id);
-  commit_proto->set_client_defined_unique_tag(entity_data.client_tag_hash);
+  // Populate client_defined_unique_tag only for non-bookmark data types.
+  if (!entity_data.specifics.has_bookmark()) {
+    commit_proto->set_client_defined_unique_tag(entity_data.client_tag_hash);
+  }
   commit_proto->set_version(commit_entity.base_version);
   commit_proto->set_deleted(entity_data.is_deleted());
   commit_proto->set_folder(entity_data.is_folder);
diff --git a/components/sync/protocol/BUILD.gn b/components/sync/protocol/BUILD.gn
index 50c3e7f..9b967ac 100644
--- a/components/sync/protocol/BUILD.gn
+++ b/components/sync/protocol/BUILD.gn
@@ -9,3 +9,8 @@
   sources = sync_protocol_sources
   extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
+
+group("chromiumsync_pyproto") {
+  # Python proto files used by components/sync/tools/testserver/chromiumsync.py
+  data = sync_protocol_pyprotos
+}
diff --git a/components/sync/protocol/protocol_sources.gni b/components/sync/protocol/protocol_sources.gni
index f5ab3954..2b1b740 100644
--- a/components/sync/protocol/protocol_sources.gni
+++ b/components/sync/protocol/protocol_sources.gni
@@ -2,57 +2,66 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-sync_protocol_sources = [
-  "//components/sync/protocol/app_notification_specifics.proto",
-  "//components/sync/protocol/app_setting_specifics.proto",
-  "//components/sync/protocol/app_specifics.proto",
-  "//components/sync/protocol/app_list_specifics.proto",
-  "//components/sync/protocol/arc_package_specifics.proto",
-  "//components/sync/protocol/article_specifics.proto",
-  "//components/sync/protocol/autofill_specifics.proto",
-  "//components/sync/protocol/bookmark_model_metadata.proto",
-  "//components/sync/protocol/bookmark_specifics.proto",
-  "//components/sync/protocol/client_commands.proto",
-  "//components/sync/protocol/client_debug_info.proto",
-  "//components/sync/protocol/device_info_specifics.proto",
-  "//components/sync/protocol/dictionary_specifics.proto",
-  "//components/sync/protocol/encryption.proto",
-  "//components/sync/protocol/entity_metadata.proto",
-  "//components/sync/protocol/experiment_status.proto",
-  "//components/sync/protocol/experiments_specifics.proto",
-  "//components/sync/protocol/extension_setting_specifics.proto",
-  "//components/sync/protocol/extension_specifics.proto",
-  "//components/sync/protocol/favicon_image_specifics.proto",
-  "//components/sync/protocol/favicon_tracking_specifics.proto",
-  "//components/sync/protocol/get_updates_caller_info.proto",
-  "//components/sync/protocol/history_delete_directive_specifics.proto",
-  "//components/sync/protocol/history_status.proto",
-  "//components/sync/protocol/loopback_server.proto",
-  "//components/sync/protocol/managed_user_setting_specifics.proto",
-  "//components/sync/protocol/managed_user_shared_setting_specifics.proto",
-  "//components/sync/protocol/managed_user_specifics.proto",
-  "//components/sync/protocol/managed_user_whitelist_specifics.proto",
-  "//components/sync/protocol/model_type_state.proto",
-  "//components/sync/protocol/model_type_store_schema_descriptor.proto",
-  "//components/sync/protocol/mountain_share_specifics.proto",
-  "//components/sync/protocol/nigori_specifics.proto",
-  "//components/sync/protocol/password_specifics.proto",
-  "//components/sync/protocol/preference_specifics.proto",
-  "//components/sync/protocol/printer_specifics.proto",
-  "//components/sync/protocol/priority_preference_specifics.proto",
-  "//components/sync/protocol/reading_list_specifics.proto",
-  "//components/sync/protocol/search_engine_specifics.proto",
-  "//components/sync/protocol/session_specifics.proto",
-  "//components/sync/protocol/sync.proto",
-  "//components/sync/protocol/sync_enums.proto",
-  "//components/sync/protocol/synced_notification_app_info_specifics.proto",
-  "//components/sync/protocol/synced_notification_specifics.proto",
-  "//components/sync/protocol/test.proto",
-  "//components/sync/protocol/theme_specifics.proto",
-  "//components/sync/protocol/typed_url_specifics.proto",
-  "//components/sync/protocol/unique_position.proto",
-  "//components/sync/protocol/user_consent_specifics.proto",
-  "//components/sync/protocol/user_consent_types.proto",
-  "//components/sync/protocol/user_event_specifics.proto",
-  "//components/sync/protocol/wifi_credential_specifics.proto",
+sync_protocol_bases = [
+  "app_notification_specifics",
+  "app_setting_specifics",
+  "app_specifics",
+  "app_list_specifics",
+  "arc_package_specifics",
+  "article_specifics",
+  "autofill_specifics",
+  "bookmark_model_metadata",
+  "bookmark_specifics",
+  "client_commands",
+  "client_debug_info",
+  "device_info_specifics",
+  "dictionary_specifics",
+  "encryption",
+  "entity_metadata",
+  "experiment_status",
+  "experiments_specifics",
+  "extension_setting_specifics",
+  "extension_specifics",
+  "favicon_image_specifics",
+  "favicon_tracking_specifics",
+  "get_updates_caller_info",
+  "history_delete_directive_specifics",
+  "history_status",
+  "loopback_server",
+  "managed_user_setting_specifics",
+  "managed_user_shared_setting_specifics",
+  "managed_user_specifics",
+  "managed_user_whitelist_specifics",
+  "model_type_state",
+  "model_type_store_schema_descriptor",
+  "mountain_share_specifics",
+  "nigori_specifics",
+  "password_specifics",
+  "preference_specifics",
+  "printer_specifics",
+  "priority_preference_specifics",
+  "reading_list_specifics",
+  "search_engine_specifics",
+  "session_specifics",
+  "sync",
+  "sync_enums",
+  "synced_notification_app_info_specifics",
+  "synced_notification_specifics",
+  "test",
+  "theme_specifics",
+  "typed_url_specifics",
+  "unique_position",
+  "user_consent_specifics",
+  "user_consent_types",
+  "user_event_specifics",
+  "wifi_credential_specifics",
 ]
+
+sync_protocol_sources = []
+sync_protocol_pyprotos = []
+
+foreach(base, sync_protocol_bases) {
+  sync_protocol_sources += [ "//components/sync/protocol/${base}.proto" ]
+  sync_protocol_pyprotos +=
+      [ "$root_out_dir/pyproto/components/sync/protocol/${base}_pb2.py" ]
+}
diff --git a/components/ui_devtools/devtools_server.cc b/components/ui_devtools/devtools_server.cc
index 294e430..6827164 100644
--- a/components/ui_devtools/devtools_server.cc
+++ b/components/ui_devtools/devtools_server.cc
@@ -133,10 +133,11 @@
     return;
 
   constexpr int kBacklog = 1;
+  auto request = mojo::MakeRequest(&server_socket);
   network_context->CreateTCPServerSocket(
       net::IPEndPoint(address, port_), kBacklog,
       net::MutableNetworkTrafficAnnotationTag(kUIDevtoolsServer),
-      mojo::MakeRequest(&server_socket),
+      std::move(request),
       base::BindOnce(&UiDevToolsServer::MakeServer,
                      weak_ptr_factory_.GetWeakPtr(), std::move(server_socket)));
 }
diff --git a/components/variations/net/variations_http_headers.cc b/components/variations/net/variations_http_headers.cc
index 790856b..c7fb6981 100644
--- a/components/variations/net/variations_http_headers.cc
+++ b/components/variations/net/variations_http_headers.cc
@@ -45,8 +45,6 @@
     "googleweblight.com",
 };
 
-const char kClientData[] = "X-Client-Data";
-
 // The result of checking if a URL should have variations headers appended.
 // This enum is used to record UMA histogram values, and should not be
 // reordered.
@@ -101,12 +99,14 @@
 void RemoveVariationsHeader(const net::RedirectInfo& redirect_info,
                             const network::ResourceResponseHead& response_head,
                             std::vector<std::string>* to_be_removed_headers) {
-  if (!internal::ShouldAppendVariationHeaders(redirect_info.new_url))
-    to_be_removed_headers->push_back(kClientData);
+  if (!ShouldAppendVariationHeaders(redirect_info.new_url))
+    to_be_removed_headers->push_back(kClientDataHeader);
 }
 
 }  // namespace
 
+const char kClientDataHeader[] = "X-Client-Data";
+
 bool AppendVariationHeaders(const GURL& url,
                             InIncognito incognito,
                             SignedIn signed_in,
@@ -119,17 +119,15 @@
   //         international TLD domains *.google.<TLD> or *.youtube.<TLD>.
   // 2. Only transmit for non-Incognito profiles.
   // 3. For the X-Client-Data header, only include non-empty variation IDs.
-  if ((incognito == InIncognito::kYes) ||
-      !internal::ShouldAppendVariationHeaders(url)) {
+  if ((incognito == InIncognito::kYes) || !ShouldAppendVariationHeaders(url))
     return false;
-  }
 
   const std::string variation_ids_header =
       VariationsHttpHeaderProvider::GetInstance()->GetClientDataHeader(
           signed_in == SignedIn::kYes);
   if (!variation_ids_header.empty()) {
     // Note that prior to M33 this header was named X-Chrome-Variations.
-    headers->SetHeaderIfMissing(kClientData, variation_ids_header);
+    headers->SetHeaderIfMissing(kClientDataHeader, variation_ids_header);
     return true;
   }
   return false;
@@ -145,13 +143,13 @@
 
 std::set<std::string> GetVariationHeaderNames() {
   std::set<std::string> headers;
-  headers.insert(kClientData);
+  headers.insert(kClientDataHeader);
   return headers;
 }
 
 void StripVariationHeaderIfNeeded(const GURL& new_location,
                                   net::URLRequest* request) {
-  if (!internal::ShouldAppendVariationHeaders(new_location)) {
+  if (!ShouldAppendVariationHeaders(new_location)) {
     for (const std::string& header : GetVariationHeaderNames())
       request->RemoveRequestHeaderByName(header);
   }
@@ -183,9 +181,6 @@
       std::move(request), incognito, SignedIn::kNo, annotation_tag);
 }
 
-namespace internal {
-
-// static
 bool ShouldAppendVariationHeaders(const GURL& url) {
   if (!url.is_valid()) {
     LogUrlValidationHistogram(INVALID_URL);
@@ -209,6 +204,4 @@
   return true;
 }
 
-}  // namespace internal
-
 }  // namespace variations
diff --git a/components/variations/net/variations_http_headers.h b/components/variations/net/variations_http_headers.h
index f7c783e..402afa3 100644
--- a/components/variations/net/variations_http_headers.h
+++ b/components/variations/net/variations_http_headers.h
@@ -28,6 +28,9 @@
 
 enum class SignedIn { kNo, kYes };
 
+// The name string for the header for variations information.
+extern const char kClientDataHeader[];
+
 // Adds Chrome experiment and metrics state as custom headers to |headers|.
 // The content of the headers will depend on |incognito| and |signed_in|
 // parameters. It is fine to pass SignedIn::NO if the state is not known to the
@@ -75,15 +78,11 @@
     InIncognito incognito,
     const net::NetworkTrafficAnnotationTag& annotation_tag);
 
-namespace internal {
-
 // Checks whether variation headers should be appended to requests to the
 // specified |url|. Returns true for google.<TLD> and youtube.<TLD> URLs with
 // the https scheme.
 bool ShouldAppendVariationHeaders(const GURL& url);
 
-}  // namespace internal
-
 }  // namespace variations
 
 #endif  // COMPONENTS_VARIATIONS_NET_VARIATIONS_HTTP_HEADERS_H_
diff --git a/components/variations/net/variations_http_headers_unittest.cc b/components/variations/net/variations_http_headers_unittest.cc
index 1469550..3a94444 100644
--- a/components/variations/net/variations_http_headers_unittest.cc
+++ b/components/variations/net/variations_http_headers_unittest.cc
@@ -148,8 +148,7 @@
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
     const GURL url(cases[i].url);
-    EXPECT_EQ(cases[i].should_append_headers,
-              internal::ShouldAppendVariationHeaders(url))
+    EXPECT_EQ(cases[i].should_append_headers, ShouldAppendVariationHeaders(url))
         << url;
   }
 }
diff --git a/components/variations/variations_http_header_provider.cc b/components/variations/variations_http_header_provider.cc
index 5055b9e3..0b1e4c8 100644
--- a/components/variations/variations_http_header_provider.cc
+++ b/components/variations/variations_http_header_provider.cc
@@ -101,6 +101,14 @@
   return ForceIdsResult::SUCCESS;
 }
 
+void VariationsHttpHeaderProvider::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void VariationsHttpHeaderProvider::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
 void VariationsHttpHeaderProvider::ResetForTesting() {
   base::AutoLock scoped_lock(lock_);
 
@@ -205,6 +213,11 @@
   // with such discrepancies.
   cached_variation_ids_header_ = GenerateBase64EncodedProto(false);
   cached_variation_ids_header_signed_in_ = GenerateBase64EncodedProto(true);
+
+  for (auto& observer : observer_list_) {
+    observer.VariationIdsHeaderUpdated(cached_variation_ids_header_,
+                                       cached_variation_ids_header_signed_in_);
+  }
 }
 
 std::string VariationsHttpHeaderProvider::GenerateBase64EncodedProto(
diff --git a/components/variations/variations_http_header_provider.h b/components/variations/variations_http_header_provider.h
index 8bf60c2..9ee5aa6 100644
--- a/components/variations/variations_http_header_provider.h
+++ b/components/variations/variations_http_header_provider.h
@@ -13,6 +13,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/observer_list.h"
 #include "base/synchronization/lock.h"
 #include "components/variations/synthetic_trials.h"
 #include "components/variations/variations_associated_data.h"
@@ -30,6 +31,17 @@
 class VariationsHttpHeaderProvider : public base::FieldTrialList::Observer,
                                      public SyntheticTrialObserver {
  public:
+  class Observer {
+   public:
+    // Called when variation ids headers are updated.
+    virtual void VariationIdsHeaderUpdated(
+        const std::string& variation_ids_header,
+        const std::string& variation_ids_header_signed_in) {}
+
+   protected:
+    virtual ~Observer() {}
+  };
+
   static VariationsHttpHeaderProvider* GetInstance();
 
   // Returns the value of the client data header, computing and caching it if
@@ -61,6 +73,10 @@
       const std::vector<std::string>& variation_ids,
       const std::string& command_line_variation_ids);
 
+  // Methods to register or remove observers of variation ids header update.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   // Resets any cached state for tests.
   void ResetForTesting();
 
@@ -140,6 +156,10 @@
   std::string cached_variation_ids_header_;
   std::string cached_variation_ids_header_signed_in_;
 
+  // List of observers to notify on variation ids header update.
+  // Makes sure list is empty on destruction.
+  base::ObserverList<Observer, true> observer_list_;
+
   DISALLOW_COPY_AND_ASSIGN(VariationsHttpHeaderProvider);
 };
 
diff --git a/components/viz/client/hit_test_data_provider_draw_quad.cc b/components/viz/client/hit_test_data_provider_draw_quad.cc
index 5d9947b8..822e04d 100644
--- a/components/viz/client/hit_test_data_provider_draw_quad.cc
+++ b/components/viz/client/hit_test_data_provider_draw_quad.cc
@@ -27,9 +27,11 @@
   for (const auto& render_pass : compositor_frame.render_pass_list) {
     // Skip the render_pass if the transform is not invertible (i.e. it will not
     // be able to receive events).
+    gfx::Transform transform_to_root_target =
+        render_pass->transform_to_root_target;
+    transform_to_root_target.FlattenTo2d();
     gfx::Transform transform_from_root_target;
-    if (!render_pass->transform_to_root_target.GetInverse(
-            &transform_from_root_target)) {
+    if (!transform_to_root_target.GetInverse(&transform_from_root_target)) {
       continue;
     }
 
@@ -49,9 +51,11 @@
 
         // Skip the quad if the transform is not invertible (i.e. it will not
         // be able to receive events).
+        gfx::Transform quad_to_target_transform =
+            quad->shared_quad_state->quad_to_target_transform;
+        quad_to_target_transform.FlattenTo2d();
         gfx::Transform target_to_quad_transform;
-        if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
-                &target_to_quad_transform)) {
+        if (!quad_to_target_transform.GetInverse(&target_to_quad_transform)) {
           continue;
         }
 
diff --git a/components/viz/service/surfaces/surface_hittest.cc b/components/viz/service/surfaces/surface_hittest.cc
index 83d97e9..83d6b0b 100644
--- a/components/viz/service/surfaces/surface_hittest.cc
+++ b/components/viz/service/surfaces/surface_hittest.cc
@@ -70,8 +70,9 @@
   // embedded in target_surface_id, or vice versa.
   if (GetTransformToTargetSurface(target_surface_id, original_surface_id,
                                   &transform)) {
-    if (transform.GetInverse(&transform))
-      transform.TransformPoint(point);
+    gfx::Transform inverse_transform;
+    if (transform.GetInverse(&inverse_transform))
+      inverse_transform.TransformPoint(point);
     else
       return false;
   } else if (GetTransformToTargetSurface(original_surface_id, target_surface_id,
@@ -105,11 +106,13 @@
 
   referenced_passes->insert(render_pass);
 
-  // The |transform_to_root_target| matrix cannot be inverted if it has a
-  // z-scale of 0 or due to floating point errors.
+  // The |transform_to_root_target| matrix may have no back-projection if the
+  // forward projection is degenerate.
   gfx::Transform transform_from_root_target;
-  if (!render_pass->transform_to_root_target.GetInverse(
-          &transform_from_root_target)) {
+  gfx::Transform transform_to_root_target =
+      render_pass->transform_to_root_target;
+  transform_to_root_target.FlattenTo2d();
+  if (!transform_to_root_target.GetInverse(&transform_from_root_target)) {
     return false;
   }
 
@@ -234,19 +237,23 @@
 
   referenced_passes->insert(render_pass);
 
-  // The |transform_to_root_target| matrix cannot be inverted if it has a
-  // z-scale of 0 or due to floating point errors.
+  // The |transform_to_root_target| matrix may have no back-projection if the
+  // forward projection is degenerate.
   gfx::Transform transform_from_root_target;
-  if (!render_pass->transform_to_root_target.GetInverse(
-          &transform_from_root_target)) {
+  gfx::Transform transform_to_root_target =
+      render_pass->transform_to_root_target;
+  transform_to_root_target.FlattenTo2d();
+  if (!transform_to_root_target.GetInverse(&transform_from_root_target)) {
     return false;
   }
 
   for (const DrawQuad* quad : render_pass->quad_list) {
     if (quad->material == DrawQuad::SURFACE_CONTENT) {
       gfx::Transform target_to_quad_transform;
-      if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
-              &target_to_quad_transform)) {
+      gfx::Transform quad_to_target_transform =
+          quad->shared_quad_state->quad_to_target_transform;
+      quad_to_target_transform.FlattenTo2d();
+      if (!quad_to_target_transform.GetInverse(&target_to_quad_transform)) {
         return false;
       }
 
@@ -326,8 +333,9 @@
 
   // We now transform the point to content space and test if it hits the
   // rect.
-  if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
-          target_to_quad_transform)) {
+  gfx::Transform transform = quad->shared_quad_state->quad_to_target_transform;
+  transform.FlattenTo2d();
+  if (!transform.GetInverse(target_to_quad_transform)) {
     return false;
   }
 
diff --git a/components/viz/service/surfaces/surface_hittest_unittest.cc b/components/viz/service/surfaces/surface_hittest_unittest.cc
index f3ed3b67..00c930e 100644
--- a/components/viz/service/surfaces/surface_hittest_unittest.cc
+++ b/components/viz/service/surfaces/surface_hittest_unittest.cc
@@ -561,4 +561,96 @@
   EXPECT_EQ(2, accept_delegate.accept_target_overrides());
 }
 
+// Hit test against a child surface that has a non-flat transform. This
+// verifies that the transform is flattened before hit testing.
+TEST_F(SurfaceHittestTest, Hittest_ChildSurfaceWithNonFlatTransform) {
+  // Creates a root surface.
+  gfx::Rect root_rect(300, 300);
+  RenderPass* root_pass = nullptr;
+  CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass);
+
+  // Add a reference to the child surface on the root surface.
+  ParentLocalSurfaceIdAllocator child_allocator;
+  SurfaceId child_surface_id(kChildFrameSink,
+                             child_allocator.GetCurrentLocalSurfaceId());
+  gfx::Rect child_rect(200, 200);
+  CreateSurfaceDrawQuad(
+      root_pass,
+      gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 1.0f,
+                     0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1.0f),
+      root_rect, child_rect, child_surface_id);
+
+  // Submit the root frame.
+  ParentLocalSurfaceIdAllocator root_allocator;
+  SurfaceId root_surface_id(kRootFrameSink,
+                            root_allocator.GetCurrentLocalSurfaceId());
+  root_support().SubmitCompositorFrame(
+      root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
+
+  // Creates a child surface.
+  RenderPass* child_pass = nullptr;
+  CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass);
+
+  // Add a solid quad in the child surface.
+  gfx::Rect child_solid_quad_rect(100, 100);
+  CreateSolidColorDrawQuad(
+      child_pass,
+      gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f,
+                     0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+      root_rect, child_solid_quad_rect);
+
+  // Submit the frame.
+  child_support().SubmitCompositorFrame(
+      child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame));
+
+  TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
+                       gfx::Point(10, 10), false},
+                      {root_surface_id, gfx::Point(99, 99), root_surface_id,
+                       gfx::Point(99, 99), true},
+                      {root_surface_id, gfx::Point(100, 100), child_surface_id,
+                       gfx::Point(50, 50), true},
+                      {root_surface_id, gfx::Point(199, 199), child_surface_id,
+                       gfx::Point(149, 149), true},
+                      {root_surface_id, gfx::Point(200, 200), root_surface_id,
+                       gfx::Point(200, 200), true},
+                      {root_surface_id, gfx::Point(290, 290), root_surface_id,
+                       gfx::Point(290, 290), false}};
+
+  RunTests(nullptr, surface_manager(), tests, arraysize(tests));
+
+  // Submit another root frame, with a slightly perturbed child Surface.
+  root_frame = CreateCompositorFrame(root_rect, &root_pass);
+  CreateSurfaceDrawQuad(
+      root_pass,
+      gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f,
+                     0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
+      root_rect, child_rect, child_surface_id);
+  root_support().SubmitCompositorFrame(
+      root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
+
+  // Verify that point (100, 100) no longer falls on the child surface.
+  // Verify that the transform to the child surface's space has also shifted.
+  {
+    SurfaceHittest hittest(nullptr, surface_manager());
+
+    gfx::Point point(100, 100);
+    gfx::Transform transform;
+    bool query_renderer;
+    EXPECT_EQ(root_surface_id,
+              hittest.GetTargetSurfaceAtPoint(root_surface_id, point,
+                                              &transform, &query_renderer));
+    transform.TransformPoint(&point);
+    EXPECT_EQ(gfx::Point(100, 100), point);
+    EXPECT_EQ(query_renderer, true);
+
+    gfx::Point point_in_target_space(100, 100);
+    gfx::Transform target_transform;
+    EXPECT_TRUE(hittest.GetTransformToTargetSurface(
+        root_surface_id, child_surface_id, &target_transform));
+    target_transform.TransformPoint(&point_in_target_space);
+    EXPECT_NE(transform, target_transform);
+    EXPECT_EQ(gfx::Point(25, 25), point_in_target_space);
+  }
+}
+
 }  // namespace viz
diff --git a/components/webcrypto/fuzzer_support.cc b/components/webcrypto/fuzzer_support.cc
index 06d0acd..d4460ed0 100644
--- a/components/webcrypto/fuzzer_support.cc
+++ b/components/webcrypto/fuzzer_support.cc
@@ -26,7 +26,7 @@
   InitOnce() {
     base::CommandLine::Init(0, nullptr);
     mojo::core::Init();
-    blink::Platform::Initialize(this, CurrentThread());
+    blink::Platform::CreateMainThreadAndInitialize(this);
   }
   ~InitOnce() override {}
 
diff --git a/content/browser/android/content_feature_list.cc b/content/browser/android/content_feature_list.cc
index 2cff631..a3b57a91 100644
--- a/content/browser/android/content_feature_list.cc
+++ b/content/browser/android/content_feature_list.cc
@@ -22,6 +22,7 @@
 // this array may either refer to features defined in the header of this file or
 // in other locations in the code base (e.g. content_features.h).
 const base::Feature* kFeaturesExposedToJava[] = {
+    &features::kBackgroundMediaRendererHasModerateBinding,
     &kEnhancedSelectionInsertionHandle,
 };
 
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 20e14a94..5f23089 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -168,7 +168,9 @@
 
 bool ChildProcessLauncherPriority::operator==(
     const ChildProcessLauncherPriority& other) const {
-  return background == other.background && frame_depth == other.frame_depth &&
+  return foreground == other.foreground &&
+         has_media_stream == other.has_media_stream &&
+         frame_depth == other.frame_depth &&
          intersects_viewport == other.intersects_viewport &&
          boost_for_pending_views == other.boost_for_pending_views
 #if defined(OS_ANDROID)
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 3ccccf3..9fbdfe8 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -56,7 +56,30 @@
 #endif
 
 struct ChildProcessLauncherPriority {
-  bool background;
+  ChildProcessLauncherPriority(bool foreground,
+                               bool has_media_stream,
+                               unsigned int frame_depth,
+                               bool intersects_viewport,
+                               bool boost_for_pending_views
+#if defined(OS_ANDROID)
+                               ,
+                               ChildProcessImportance importance
+#endif
+                               )
+      : foreground(foreground),
+        has_media_stream(has_media_stream),
+        frame_depth(frame_depth),
+        intersects_viewport(intersects_viewport),
+        boost_for_pending_views(boost_for_pending_views)
+#if defined(OS_ANDROID)
+        ,
+        importance(importance)
+#endif
+  {
+  }
+
+  bool foreground;
+  bool has_media_stream;
   unsigned int frame_depth;
   bool intersects_viewport;
   bool boost_for_pending_views;
@@ -64,6 +87,9 @@
   ChildProcessImportance importance;
 #endif
 
+  // Returns true if the child process is backgrounded.
+  bool is_background() const { return !foreground && !has_media_stream; }
+
   bool operator==(const ChildProcessLauncherPriority& other) const;
   bool operator!=(const ChildProcessLauncherPriority& other) const {
     return !(*this == other);
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc
index a368f8c..f1fa1ab 100644
--- a/content/browser/child_process_launcher_helper_android.cc
+++ b/content/browser/child_process_launcher_helper_android.cc
@@ -221,9 +221,10 @@
   JNIEnv* env = AttachCurrentThread();
   DCHECK(env);
   return Java_ChildProcessLauncherHelperImpl_setPriority(
-      env, java_peer_, process.Handle(), !priority.background,
-      priority.frame_depth, priority.intersects_viewport,
-      priority.boost_for_pending_views, static_cast<jint>(priority.importance));
+      env, java_peer_, process.Handle(), priority.foreground,
+      priority.has_media_stream, priority.frame_depth,
+      priority.intersects_viewport, priority.boost_for_pending_views,
+      static_cast<jint>(priority.importance));
 }
 
 // static
diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc
index 82a6e9f..c981f7f 100644
--- a/content/browser/child_process_launcher_helper_linux.cc
+++ b/content/browser/child_process_launcher_helper_linux.cc
@@ -158,7 +158,7 @@
     const ChildProcessLauncherPriority& priority) {
   DCHECK(CurrentlyOnProcessLauncherTaskRunner());
   if (process.CanBackgroundProcesses())
-    process.SetProcessBackgrounded(priority.background);
+    process.SetProcessBackgrounded(priority.is_background());
 }
 
 // static
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc
index bd13825..c1b02ef 100644
--- a/content/browser/child_process_launcher_helper_mac.cc
+++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -269,7 +269,7 @@
     const ChildProcessLauncherPriority& priority) {
   if (process.CanBackgroundProcesses()) {
     process.SetProcessBackgrounded(MachBroker::GetInstance(),
-                                   priority.background);
+                                   priority.is_background());
   }
 }
 
diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc
index 5d81eb2..4deb943 100644
--- a/content/browser/child_process_launcher_helper_win.cc
+++ b/content/browser/child_process_launcher_helper_win.cc
@@ -115,7 +115,7 @@
     const ChildProcessLauncherPriority& priority) {
   DCHECK(CurrentlyOnProcessLauncherTaskRunner());
   if (process.CanBackgroundProcesses())
-    process.SetProcessBackgrounded(priority.background);
+    process.SetProcessBackgrounded(priority.is_background());
 }
 
 // static
diff --git a/content/browser/fileapi/fileapi_message_filter.cc b/content/browser/fileapi/fileapi_message_filter.cc
index 1e42768..11c3863f8 100644
--- a/content/browser/fileapi/fileapi_message_filter.cc
+++ b/content/browser/fileapi/fileapi_message_filter.cc
@@ -29,8 +29,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "ipc/ipc_platform_file.h"
 #include "net/base/mime_util.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/shareable_file_reference.h"
@@ -66,7 +64,6 @@
 
 FileAPIMessageFilter::FileAPIMessageFilter(
     int process_id,
-    net::URLRequestContextGetter* request_context_getter,
     storage::FileSystemContext* file_system_context,
     ChromeBlobStorageContext* blob_storage_context)
     : BrowserMessageFilter(kFileApiFilteredMessageClasses,
@@ -74,41 +71,14 @@
       process_id_(process_id),
       context_(file_system_context),
       security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
-      request_context_getter_(request_context_getter),
-      request_context_(nullptr),
       blob_storage_context_(blob_storage_context) {
   DCHECK(context_);
-  DCHECK(request_context_getter_.get());
-  DCHECK(blob_storage_context);
-}
-
-FileAPIMessageFilter::FileAPIMessageFilter(
-    int process_id,
-    net::URLRequestContext* request_context,
-    storage::FileSystemContext* file_system_context,
-    ChromeBlobStorageContext* blob_storage_context)
-    : BrowserMessageFilter(kFileApiFilteredMessageClasses,
-                           arraysize(kFileApiFilteredMessageClasses)),
-      process_id_(process_id),
-      context_(file_system_context),
-      security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
-      request_context_(request_context),
-      blob_storage_context_(blob_storage_context) {
-  DCHECK(context_);
-  DCHECK(request_context_);
   DCHECK(blob_storage_context);
 }
 
 void FileAPIMessageFilter::OnChannelConnected(int32_t peer_pid) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  if (request_context_getter_.get()) {
-    DCHECK(!request_context_);
-    request_context_ = request_context_getter_->GetURLRequestContext();
-    request_context_getter_ = nullptr;
-    DCHECK(request_context_);
-  }
-
   operation_runner_ = context_->CreateFileSystemOperationRunner();
 }
 
@@ -343,11 +313,6 @@
                                    const std::string& blob_uuid,
                                    int64_t offset) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (!request_context_) {
-    // We can't write w/o a request context, trying to do so will crash.
-    NOTREACHED();
-    return;
-  }
 
   FileSystemURL url(context_->CrackURL(path));
   if (!ValidateFileSystemURL(request_id, url))
@@ -362,7 +327,7 @@
       blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
 
   operations_[request_id] = operation_runner()->Write(
-      request_context_, url, std::move(blob), offset,
+      url, std::move(blob), offset,
       base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
 }
 
diff --git a/content/browser/fileapi/fileapi_message_filter.h b/content/browser/fileapi/fileapi_message_filter.h
index 7188c68..d6b37f6 100644
--- a/content/browser/fileapi/fileapi_message_filter.h
+++ b/content/browser/fileapi/fileapi_message_filter.h
@@ -41,11 +41,6 @@
 struct FileSystemInfo;
 }
 
-namespace net {
-class URLRequestContext;
-class URLRequestContextGetter;
-}  // namespace net
-
 namespace storage {
 class ShareableFileReference;
 }
@@ -58,14 +53,7 @@
 // FileAPIMessageFilter into separate classes. See crbug.com/263741.
 class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
  public:
-  // Used by the renderer process host on the UI thread.
   FileAPIMessageFilter(int process_id,
-                       net::URLRequestContextGetter* request_context_getter,
-                       storage::FileSystemContext* file_system_context,
-                       ChromeBlobStorageContext* blob_storage_context);
-  // Used by the worker process host on the IO thread.
-  FileAPIMessageFilter(int process_id,
-                       net::URLRequestContext* request_context,
                        storage::FileSystemContext* file_system_context,
                        ChromeBlobStorageContext* blob_storage_context);
 
@@ -168,11 +156,6 @@
   typedef std::map<int, OperationID> OperationsMap;
   OperationsMap operations_;
 
-  // The getter holds the context until OnChannelConnected() can be called from
-  // the IO thread, which will extract the net::URLRequestContext from it.
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  net::URLRequestContext* request_context_;
-
   scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
 
   std::unique_ptr<storage::FileSystemOperationRunner> operation_runner_;
diff --git a/content/browser/fileapi/fileapi_message_filter_unittest.cc b/content/browser/fileapi/fileapi_message_filter_unittest.cc
index c996e7c..5302dee 100644
--- a/content/browser/fileapi/fileapi_message_filter_unittest.cc
+++ b/content/browser/fileapi/fileapi_message_filter_unittest.cc
@@ -55,8 +55,6 @@
 
     filter_ = new FileAPIMessageFilter(
         0 /* process_id */,
-        BrowserContext::GetDefaultStoragePartition(&browser_context_)
-            ->GetURLRequestContext(),
         file_system_context_.get(), blob_storage_context_);
 
     // Complete initialization.
@@ -74,8 +72,6 @@
 TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
   scoped_refptr<FileAPIMessageFilter> filter(new FileAPIMessageFilter(
       0 /* process_id */,
-      BrowserContext::GetDefaultStoragePartition(&browser_context_)
-          ->GetURLRequestContext(),
       file_system_context_.get(),
       ChromeBlobStorageContext::GetFor(&browser_context_)));
   filter->OnChannelConnected(0);
@@ -98,14 +94,10 @@
 TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
   scoped_refptr<FileAPIMessageFilter> filter1(new FileAPIMessageFilter(
       0 /* process_id */,
-      BrowserContext::GetDefaultStoragePartition(&browser_context_)
-          ->GetURLRequestContext(),
       file_system_context_.get(),
       ChromeBlobStorageContext::GetFor(&browser_context_)));
   scoped_refptr<FileAPIMessageFilter> filter2(new FileAPIMessageFilter(
       1 /* process_id */,
-      BrowserContext::GetDefaultStoragePartition(&browser_context_)
-          ->GetURLRequestContext(),
       file_system_context_.get(),
       ChromeBlobStorageContext::GetFor(&browser_context_)));
   filter1->OnChannelConnected(0);
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index a64a441..0277986 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -226,6 +226,9 @@
       NewDescriptionValuePair("Driver version", active_gpu.driver_version));
   basic_info->Append(
       NewDescriptionValuePair("Driver date", active_gpu.driver_date));
+  basic_info->Append(NewDescriptionValuePair(
+      "GPU CUDA compute capability major version",
+      std::make_unique<base::Value>(active_gpu.cuda_compute_capability_major)));
   basic_info->Append(NewDescriptionValuePair("Pixel shader version",
                                              gpu_info.pixel_shader_version));
   basic_info->Append(NewDescriptionValuePair("Vertex shader version",
diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc
index 9c30505..d9c8efb 100644
--- a/content/browser/indexed_db/database_impl.cc
+++ b/content/browser/indexed_db/database_impl.cc
@@ -78,7 +78,6 @@
   void Put(int64_t transaction_id,
            int64_t object_store_id,
            ::indexed_db::mojom::ValuePtr value,
-           std::vector<std::unique_ptr<storage::BlobDataHandle>> handles,
            std::vector<IndexedDBBlobInfo> blob_info,
            const IndexedDBKey& key,
            blink::WebIDBPutMode mode,
@@ -281,8 +280,6 @@
       new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
                              std::move(callbacks_info), idb_runner_));
 
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles(
-      value->blob_or_file_info.size());
   base::CheckedNumeric<uint64_t> total_blob_size = 0;
   std::vector<IndexedDBBlobInfo> blob_info(value->blob_or_file_info.size());
   for (size_t i = 0; i < value->blob_or_file_info.size(); ++i) {
@@ -309,7 +306,6 @@
     uint64_t size = handle->size();
     UMA_HISTOGRAM_MEMORY_KB("Storage.IndexedDB.PutBlobSizeKB", size / 1024ull);
     total_blob_size += size;
-    handles[i] = std::move(handle);
 
     if (info->file) {
       if (!info->file->path.empty() &&
@@ -318,14 +314,15 @@
         mojo::ReportBadMessage(kInvalidBlobFilePath);
         return;
       }
-      blob_info[i] = IndexedDBBlobInfo(info->uuid, info->file->path,
+      blob_info[i] = IndexedDBBlobInfo(std::move(handle), info->file->path,
                                        info->file->name, info->mime_type);
       if (info->size != -1) {
         blob_info[i].set_last_modified(info->file->last_modified);
         blob_info[i].set_size(info->size);
       }
     } else {
-      blob_info[i] = IndexedDBBlobInfo(info->uuid, info->mime_type, info->size);
+      blob_info[i] =
+          IndexedDBBlobInfo(std::move(handle), info->mime_type, info->size);
     }
   }
   UMA_HISTOGRAM_COUNTS_1000("WebCore.IndexedDB.PutBlobsCount",
@@ -340,8 +337,8 @@
       FROM_HERE,
       base::BindOnce(&IDBSequenceHelper::Put, base::Unretained(helper_),
                      transaction_id, object_store_id, std::move(value),
-                     std::move(handles), std::move(blob_info), key, mode,
-                     index_keys, std::move(callbacks)));
+                     std::move(blob_info), key, mode, index_keys,
+                     std::move(callbacks)));
 }
 
 void DatabaseImpl::SetIndexKeys(
@@ -657,7 +654,6 @@
     int64_t transaction_id,
     int64_t object_store_id,
     ::indexed_db::mojom::ValuePtr mojo_value,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles,
     std::vector<IndexedDBBlobInfo> blob_info,
     const IndexedDBKey& key,
     blink::WebIDBPutMode mode,
@@ -681,7 +677,7 @@
   IndexedDBValue value;
   swap(value.bits, mojo_value->bits);
   swap(value.blob_info, blob_info);
-  connection_->database()->Put(transaction, object_store_id, &value, &handles,
+  connection_->database()->Put(transaction, object_store_id, &value,
                                std::make_unique<IndexedDBKey>(key), mode,
                                std::move(callbacks), index_keys);
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index 8fb6b84..ba773f3 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -366,10 +366,6 @@
   return false;
 }
 
-GURL GetURLFromUUID(const std::string& uuid) {
-  return GURL("blob:uuid/" + uuid);
-}
-
 Status DeleteBlobsInRange(IndexedDBBackingStore::Transaction* transaction,
                           int64_t database_id,
                           int64_t object_store_id,
@@ -390,8 +386,7 @@
       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
       return InternalInconsistencyStatus();
     }
-    transaction->PutBlobInfo(database_id, object_store_id, user_key, nullptr,
-                             nullptr);
+    transaction->PutBlobInfo(database_id, object_store_id, user_key, nullptr);
   }
   return s;
 }
@@ -1288,7 +1283,6 @@
     int64_t object_store_id,
     const IndexedDBKey& key,
     IndexedDBValue* value,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
     RecordIdentifier* record_identifier) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
@@ -1312,14 +1306,10 @@
   v.append(value->bits);
 
   leveldb_transaction->Put(object_store_data_key, &v);
-  s = transaction->PutBlobInfoIfNeeded(database_id,
-                                       object_store_id,
-                                       object_store_data_key,
-                                       &value->blob_info,
-                                       handles);
+  s = transaction->PutBlobInfoIfNeeded(
+      database_id, object_store_id, object_store_data_key, &value->blob_info);
   if (!s.ok())
     return s;
-  DCHECK(handles->empty());
 
   const std::string exists_entry_key =
       ExistsEntryKey::Encode(database_id, object_store_id, key);
@@ -1369,8 +1359,8 @@
   const std::string object_store_data_key = ObjectStoreDataKey::Encode(
       database_id, object_store_id, record_identifier.primary_key());
   leveldb_transaction->Remove(object_store_data_key);
-  Status s = transaction->PutBlobInfoIfNeeded(
-      database_id, object_store_id, object_store_data_key, nullptr, nullptr);
+  Status s = transaction->PutBlobInfoIfNeeded(database_id, object_store_id,
+                                              object_store_data_key, nullptr);
   if (!s.ok())
     return s;
 
@@ -1710,11 +1700,9 @@
     }
   }
 
-  void WriteBlobToFileOnIOThread(
-      const FilePath& file_path,
-      const GURL& blob_url,
-      const base::Time& last_modified,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
+  void WriteBlobToFileOnIOThread(const FilePath& file_path,
+                                 std::unique_ptr<storage::BlobDataHandle> blob,
+                                 const base::Time& last_modified) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
     std::unique_ptr<storage::FileStreamWriter> writer(
         storage::FileStreamWriter::CreateForLocalFile(
@@ -1724,43 +1712,11 @@
         std::make_unique<FileWriterDelegate>(
             std::move(writer), storage::FlushPolicy::FLUSH_ON_COMPLETION));
 
-    DCHECK(blob_url.is_valid());
-    net::URLRequestContext* request_context =
-        request_context_getter->GetURLRequestContext();
-    net::NetworkTrafficAnnotationTag traffic_annotation =
-        net::DefineNetworkTrafficAnnotation("persist_blob_to_indexed_db", R"(
-        semantics {
-          sender: "Indexed DB"
-          description:
-            "A web page's script has created a Blob (or File) object (either "
-            "directly via constructors, or by using file upload to a form, or "
-            "via a fetch()). The script has then made a request to store data "
-            "including the Blob via the Indexed DB API. As part of committing "
-            "the database transaction, the content of the Blob is being copied "
-            "into a file in the database's directory."
-          trigger:
-            "The script has made a request to store data including a Blob via "
-            "the Indexed DB API."
-          data:
-            "A Blob or File object referenced by script, either created "
-            "directly via constructors, or by using file upload to a form, or "
-            "drag/drop, or via a fetch() or other APIs that produce Blobs."
-          destination: LOCAL
-        }
-        policy {
-          cookies_allowed: NO
-          setting: "This feature cannot be disabled by settings."
-          policy_exception_justification: "Not implemented."
-        })");
-    std::unique_ptr<net::URLRequest> blob_request(
-        request_context->CreateRequest(blob_url, net::DEFAULT_PRIORITY,
-                                       delegate.get(), traffic_annotation));
-    blob_request->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
-                               net::LOAD_DO_NOT_SEND_COOKIES);
+    DCHECK(blob);
     this->file_path_ = file_path;
     this->last_modified_ = last_modified;
 
-    delegate->Start(std::move(blob_request),
+    delegate->Start(blob->CreateReader(),
                     base::Bind(&LocalWriteClosure::Run, this));
     chained_blob_writer_->set_delegate(std::move(delegate));
   }
@@ -1849,14 +1805,15 @@
         base::BindOnce(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
                        chained_blob_writer, true, info.size));
   } else {
-    DCHECK(descriptor.url().is_valid());
+    DCHECK(descriptor.blob());
     scoped_refptr<LocalWriteClosure> write_closure(
         new LocalWriteClosure(chained_blob_writer, task_runner_.get()));
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&LocalWriteClosure::WriteBlobToFileOnIOThread,
-                       write_closure, path, descriptor.url(),
-                       descriptor.last_modified(), request_context_getter_));
+        base::BindOnce(
+            &LocalWriteClosure::WriteBlobToFileOnIOThread, write_closure, path,
+            std::make_unique<storage::BlobDataHandle>(*descriptor.blob()),
+            descriptor.last_modified()));
   }
   return true;
 }
@@ -3139,8 +3096,8 @@
                             entry.last_modified()));
       } else {
         new_files_to_write->push_back(
-            WriteDescriptor(GetURLFromUUID(entry.uuid()), next_blob_key,
-                            entry.size(), entry.last_modified()));
+            WriteDescriptor(entry.blob_handle(), next_blob_key, entry.size(),
+                            entry.last_modified()));
       }
       entry.set_key(next_blob_key);
       new_blob_keys.push_back(&entry);
@@ -3454,23 +3411,12 @@
     blob_info_.swap(*blob_info);
 }
 
-void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
-  handles_.clear();
-  if (handles)
-    handles_.swap(*handles);
-}
-
 std::unique_ptr<IndexedDBBackingStore::BlobChangeRecord>
 IndexedDBBackingStore::BlobChangeRecord::Clone() const {
   std::unique_ptr<IndexedDBBackingStore::BlobChangeRecord> record(
       new BlobChangeRecord(key_, object_store_id_));
   record->blob_info_ = blob_info_;
 
-  for (const auto& handle : handles_) {
-    record->handles_.push_back(
-        std::make_unique<storage::BlobDataHandle>(*handle));
-  }
   return record;
 }
 
@@ -3478,8 +3424,7 @@
     int64_t database_id,
     int64_t object_store_id,
     const std::string& object_store_data_key,
-    std::vector<IndexedDBBlobInfo>* blob_info,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
+    std::vector<IndexedDBBlobInfo>* blob_info) {
   if (!blob_info || blob_info->empty()) {
     blob_change_map_.erase(object_store_data_key);
     incognito_blob_map_.erase(object_store_data_key);
@@ -3499,8 +3444,7 @@
     if (!found)
       return Status::OK();
   }
-  PutBlobInfo(
-      database_id, object_store_id, object_store_data_key, blob_info, handles);
+  PutBlobInfo(database_id, object_store_id, object_store_data_key, blob_info);
   return Status::OK();
 }
 
@@ -3512,8 +3456,7 @@
     int64_t database_id,
     int64_t object_store_id,
     const std::string& object_store_data_key,
-    std::vector<IndexedDBBlobInfo>* blob_info,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
+    std::vector<IndexedDBBlobInfo>* blob_info) {
   DCHECK(!object_store_data_key.empty());
   if (database_id_ < 0)
     database_id_ = database_id;
@@ -3532,21 +3475,18 @@
   }
   DCHECK_EQ(record->object_store_id(), object_store_id);
   record->SetBlobInfo(blob_info);
-  record->SetHandles(handles);
-  DCHECK(!handles || handles->empty());
 }
 
 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
-    const GURL& url,
+    const storage::BlobDataHandle* blob,
     int64_t key,
     int64_t size,
     base::Time last_modified)
     : is_file_(false),
-      url_(url),
+      blob_(*blob),
       key_(key),
       size_(size),
-      last_modified_(last_modified) {
-}
+      last_modified_(last_modified) {}
 
 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
     const FilePath& file_path,
@@ -3565,7 +3505,7 @@
 IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() =
     default;
 IndexedDBBackingStore::Transaction::WriteDescriptor&
-    IndexedDBBackingStore::Transaction::WriteDescriptor::
-    operator=(const WriteDescriptor& other) = default;
+IndexedDBBackingStore::Transaction::WriteDescriptor::operator=(
+    const WriteDescriptor& other) = default;
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 4ec5251..a473d7b 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -122,15 +122,12 @@
     const std::vector<IndexedDBBlobInfo>& blob_info() const {
       return blob_info_;
     }
-    void SetHandles(
-        std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
     std::unique_ptr<BlobChangeRecord> Clone() const;
 
    private:
     std::string key_;
     int64_t object_store_id_;
     std::vector<IndexedDBBlobInfo> blob_info_;
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles_;
     DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord);
   };
 
@@ -164,14 +161,11 @@
         int64_t database_id,
         int64_t object_store_id,
         const std::string& object_store_data_key,
-        std::vector<IndexedDBBlobInfo>*,
-        std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
-    void PutBlobInfo(
-        int64_t database_id,
-        int64_t object_store_id,
-        const std::string& object_store_data_key,
-        std::vector<IndexedDBBlobInfo>*,
-        std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
+        std::vector<IndexedDBBlobInfo>*);
+    void PutBlobInfo(int64_t database_id,
+                     int64_t object_store_id,
+                     const std::string& object_store_data_key,
+                     std::vector<IndexedDBBlobInfo>*);
 
     LevelDBTransaction* transaction() { return transaction_.get(); }
 
@@ -189,7 +183,7 @@
 
     class CONTENT_EXPORT WriteDescriptor {
      public:
-      WriteDescriptor(const GURL& url,
+      WriteDescriptor(const storage::BlobDataHandle* blob,
                       int64_t key,
                       int64_t size,
                       base::Time last_modified);
@@ -202,9 +196,9 @@
       WriteDescriptor& operator=(const WriteDescriptor& other);
 
       bool is_file() const { return is_file_; }
-      const GURL& url() const {
+      const storage::BlobDataHandle* blob() const {
         DCHECK(!is_file_);
-        return url_;
+        return &blob_.value();
       }
       const base::FilePath& file_path() const {
         DCHECK(is_file_);
@@ -216,7 +210,7 @@
 
      private:
       bool is_file_;
-      GURL url_;
+      base::Optional<storage::BlobDataHandle> blob_;
       base::FilePath file_path_;
       int64_t key_;
       int64_t size_;
@@ -456,7 +450,6 @@
       int64_t object_store_id,
       const IndexedDBKey& key,
       IndexedDBValue* value,
-      std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
       RecordIdentifier* record) WARN_UNUSED_RESULT;
   virtual leveldb::Status ClearObjectStore(
       IndexedDBBackingStore::Transaction* transaction,
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index eaa915e6..f65bd17 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/sequenced_task_runner.h"
@@ -28,7 +29,9 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "net/url_request/url_request_test_util.h"
+#include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "storage/browser/test/mock_quota_manager_proxy.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
@@ -330,13 +333,15 @@
   void SetUp() override {
     IndexedDBBackingStoreTest::SetUp();
 
+    blob_context_ = std::make_unique<storage::BlobStorageContext>();
+
     // useful keys and values during tests
     blob_info_.push_back(
-        IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
+        IndexedDBBlobInfo(CreateBlob(), base::UTF8ToUTF16("blob type"), 1));
     blob_info_.push_back(IndexedDBBlobInfo(
-        "uuid 4", base::FilePath(FILE_PATH_LITERAL("path/to/file")),
+        CreateBlob(), base::FilePath(FILE_PATH_LITERAL("path/to/file")),
         base::UTF8ToUTF16("file name"), base::UTF8ToUTF16("file type")));
-    blob_info_.push_back(IndexedDBBlobInfo("uuid 5", base::FilePath(),
+    blob_info_.push_back(IndexedDBBlobInfo(CreateBlob(), base::FilePath(),
                                            base::UTF8ToUTF16("file name"),
                                            base::UTF8ToUTF16("file type")));
     value3_ = IndexedDBValue("value3", blob_info_);
@@ -344,6 +349,11 @@
     key3_ = IndexedDBKey(ASCIIToUTF16("key3"));
   }
 
+  std::unique_ptr<storage::BlobDataHandle> CreateBlob() {
+    return blob_context_->AddFinishedBlob(
+        std::make_unique<storage::BlobDataBuilder>(base::GenerateGUID()));
+  }
+
   // This just checks the data that survive getting stored and recalled, e.g.
   // the file path and UUID will change and thus aren't verified.
   bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
@@ -403,7 +413,7 @@
         if (desc.file_path() != info.file_path())
           return false;
       } else {
-        if (desc.url() != GURL("blob:uuid/" + info.uuid()))
+        if (desc.blob()->uuid() != info.blob_handle()->uuid())
           return false;
       }
     }
@@ -428,6 +438,8 @@
   IndexedDBValue value3_;
 
  private:
+  std::unique_ptr<storage::BlobStorageContext> blob_context_;
+
   // Blob details referenced by |value3_|. The various CheckBlob*() methods
   // can be used to verify the state as a test progresses.
   std::vector<IndexedDBBlobInfo> blob_info_;
@@ -470,10 +482,9 @@
             {
               IndexedDBBackingStore::Transaction transaction1(backing_store);
               transaction1.Begin();
-              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
               IndexedDBBackingStore::RecordIdentifier record;
               leveldb::Status s = backing_store->PutRecord(
-                  &transaction1, 1, 1, key, &value, &handles, &record);
+                  &transaction1, 1, 1, key, &value, &record);
               EXPECT_TRUE(s.ok());
               scoped_refptr<TestCallback> callback(
                   base::MakeRefCounted<TestCallback>());
@@ -521,12 +532,10 @@
                 std::make_unique<IndexedDBBackingStore::Transaction>(
                     test->backing_store());
             state->transaction1->Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
             IndexedDBBackingStore::RecordIdentifier record;
             EXPECT_TRUE(test->backing_store()
                             ->PutRecord(state->transaction1.get(), 1, 1,
-                                        test->key3_, &test->value3_, &handles,
-                                        &record)
+                                        test->key3_, &test->value3_, &record)
                             .ok());
             state->callback1 = base::MakeRefCounted<TestCallback>();
             EXPECT_TRUE(
@@ -599,7 +608,7 @@
   RunAllTasksUntilIdle();
 }
 
-TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
+TEST_F(IndexedDBBackingStoreTestWithBlobs, DeleteRange) {
   const std::vector<IndexedDBKey> keys = {
       IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
       IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3"))};
@@ -620,8 +629,12 @@
       scoped_refptr<TestCallback> callback1;
       std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
       scoped_refptr<TestCallback> callback2;
+      std::vector<std::unique_ptr<storage::BlobDataHandle>> blobs;
     } state;
 
+    for (size_t j = 0; j < 4; ++j)
+      state.blobs.push_back(CreateBlob());
+
     idb_context_->TaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(
@@ -633,19 +646,26 @@
               backing_store->ClearRemovals();
 
               std::vector<IndexedDBValue> values = {
-                  IndexedDBValue(
-                      "value0", {IndexedDBBlobInfo(
-                                    "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
-                  IndexedDBValue(
-                      "value1", {IndexedDBBlobInfo(
-                                    "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
-                  IndexedDBValue(
-                      "value2", {IndexedDBBlobInfo(
-                                    "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
-                  IndexedDBValue(
-                      "value3",
-                      {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
-                                         1)})};
+                  IndexedDBValue("value0",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[0]),
+                                     base::UTF8ToUTF16("type 0"), 1)}),
+                  IndexedDBValue("value1",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[1]),
+                                     base::UTF8ToUTF16("type 1"), 1)}),
+                  IndexedDBValue("value2",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[2]),
+                                     base::UTF8ToUTF16("type 2"), 1)}),
+                  IndexedDBValue("value3",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[3]),
+                                     base::UTF8ToUTF16("type 3"), 1)})};
               ASSERT_GE(keys.size(), values.size());
 
               // Initiate transaction1 - write records.
@@ -653,14 +673,12 @@
                   std::make_unique<IndexedDBBackingStore::Transaction>(
                       backing_store);
               state->transaction1->Begin();
-              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
               IndexedDBBackingStore::RecordIdentifier record;
               for (size_t i = 0; i < values.size(); ++i) {
                 EXPECT_TRUE(backing_store
                                 ->PutRecord(state->transaction1.get(),
                                             database_id, object_store_id,
-                                            keys[i], &values[i], &handles,
-                                            &record)
+                                            keys[i], &values[i], &record)
                                 .ok());
               }
 
@@ -728,7 +746,7 @@
   }
 }
 
-TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
+TEST_F(IndexedDBBackingStoreTestWithBlobs, DeleteRangeEmptyRange) {
   const std::vector<IndexedDBKey> keys = {
       IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
       IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3")),
@@ -748,8 +766,12 @@
       scoped_refptr<TestCallback> callback1;
       std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
       scoped_refptr<TestCallback> callback2;
+      std::vector<std::unique_ptr<storage::BlobDataHandle>> blobs;
     } state;
 
+    for (size_t j = 0; j < 4; ++j)
+      state.blobs.push_back(CreateBlob());
+
     idb_context_->TaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(
@@ -761,19 +783,26 @@
               backing_store->ClearRemovals();
 
               std::vector<IndexedDBValue> values = {
-                  IndexedDBValue(
-                      "value0", {IndexedDBBlobInfo(
-                                    "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
-                  IndexedDBValue(
-                      "value1", {IndexedDBBlobInfo(
-                                    "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
-                  IndexedDBValue(
-                      "value2", {IndexedDBBlobInfo(
-                                    "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
-                  IndexedDBValue(
-                      "value3",
-                      {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
-                                         1)})};
+                  IndexedDBValue("value0",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[0]),
+                                     base::UTF8ToUTF16("type 0"), 1)}),
+                  IndexedDBValue("value1",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[1]),
+                                     base::UTF8ToUTF16("type 1"), 1)}),
+                  IndexedDBValue("value2",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[2]),
+                                     base::UTF8ToUTF16("type 2"), 1)}),
+                  IndexedDBValue("value3",
+                                 {IndexedDBBlobInfo(
+                                     std::make_unique<storage::BlobDataHandle>(
+                                         *state->blobs[3]),
+                                     base::UTF8ToUTF16("type 3"), 1)})};
               ASSERT_GE(keys.size(), values.size());
 
               // Initiate transaction1 - write records.
@@ -782,14 +811,12 @@
                       backing_store);
               state->transaction1->Begin();
 
-              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
               IndexedDBBackingStore::RecordIdentifier record;
               for (size_t i = 0; i < values.size(); ++i) {
                 EXPECT_TRUE(backing_store
                                 ->PutRecord(state->transaction1.get(),
                                             database_id, object_store_id,
-                                            keys[i], &values[i], &handles,
-                                            &record)
+                                            keys[i], &values[i], &record)
                                 .ok());
               }
               // Start committing transaction1.
@@ -869,12 +896,10 @@
                 std::make_unique<IndexedDBBackingStore::Transaction>(
                     test->backing_store());
             state->transaction1->Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles1;
             IndexedDBBackingStore::RecordIdentifier record1;
             EXPECT_TRUE(test->backing_store()
                             ->PutRecord(state->transaction1.get(), 1, 1,
-                                        test->key3_, &test->value3_, &handles1,
-                                        &record1)
+                                        test->key3_, &test->value3_, &record1)
                             .ok());
             state->callback1 = base::MakeRefCounted<TestCallback>();
             EXPECT_TRUE(
@@ -898,12 +923,10 @@
                 std::make_unique<IndexedDBBackingStore::Transaction>(
                     test->backing_store());
             state->transaction2->Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles2;
             IndexedDBBackingStore::RecordIdentifier record2;
             EXPECT_TRUE(test->backing_store()
                             ->PutRecord(state->transaction2.get(), 1, 1,
-                                        test->key1_, &test->value1_, &handles2,
-                                        &record2)
+                                        test->key1_, &test->value1_, &record2)
                             .ok());
             state->callback2 = base::MakeRefCounted<TestCallback>();
             EXPECT_TRUE(
@@ -953,12 +976,10 @@
                 std::make_unique<IndexedDBBackingStore::Transaction>(
                     test->backing_store());
             state->transaction1->Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
             IndexedDBBackingStore::RecordIdentifier record;
             EXPECT_TRUE(test->backing_store()
                             ->PutRecord(state->transaction1.get(), 1, 1,
-                                        test->key3_, &test->value3_, &handles,
-                                        &record)
+                                        test->key3_, &test->value3_, &record)
                             .ok());
             state->callback1 = base::MakeRefCounted<TestCallback>();
             EXPECT_TRUE(
@@ -1081,11 +1102,10 @@
             {
               IndexedDBBackingStore::Transaction transaction1(backing_store);
               transaction1.Begin();
-              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
               IndexedDBBackingStore::RecordIdentifier record;
               leveldb::Status s = backing_store->PutRecord(
                   &transaction1, high_database_id, high_object_store_id, key1,
-                  &value1, &handles, &record);
+                  &value1, &record);
               EXPECT_TRUE(s.ok());
 
               s = backing_store->PutIndexDataForRecord(
@@ -1158,21 +1178,19 @@
             IndexedDBBackingStore::Transaction transaction1(backing_store);
             transaction1.Begin();
 
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
             IndexedDBBackingStore::RecordIdentifier record;
             leveldb::Status s = backing_store->PutRecord(
                 &transaction1, database_id, KeyPrefix::kInvalidId, key, &value,
-                &handles, &record);
+                &record);
             EXPECT_FALSE(s.ok());
             s = backing_store->PutRecord(&transaction1, database_id, 0, key,
-                                         &value, &handles, &record);
+                                         &value, &record);
             EXPECT_FALSE(s.ok());
             s = backing_store->PutRecord(&transaction1, KeyPrefix::kInvalidId,
-                                         object_store_id, key, &value, &handles,
-                                         &record);
+                                         object_store_id, key, &value, &record);
             EXPECT_FALSE(s.ok());
             s = backing_store->PutRecord(&transaction1, 0, object_store_id, key,
-                                         &value, &handles, &record);
+                                         &value, &record);
             EXPECT_FALSE(s.ok());
 
             s = backing_store->GetRecord(&transaction1, database_id,
@@ -1503,11 +1521,10 @@
             // Save a value.
             IndexedDBBackingStore::Transaction transaction1(backing_store);
             transaction1.Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
             IndexedDBBackingStore::RecordIdentifier record;
             leveldb::Status s = backing_store->PutRecord(
                 &transaction1, state->database_id, state->object_store_id, key,
-                &value, &handles, &record);
+                &value, &record);
             EXPECT_TRUE(s.ok());
             scoped_refptr<TestCallback> callback(
                 base::MakeRefCounted<TestCallback>());
@@ -1648,13 +1665,12 @@
                 std::make_unique<IndexedDBBackingStore::Transaction>(
                     test->backing_store());
             state->transaction1->Begin();
-            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
             IndexedDBBackingStore::RecordIdentifier record;
             EXPECT_TRUE(test->backing_store()
                             ->PutRecord(state->transaction1.get(),
                                         state->database_id,
                                         state->object_store_id, test->key3_,
-                                        &test->value3_, &handles, &record)
+                                        &test->value3_, &record)
                             .ok());
             state->callback1 = base::MakeRefCounted<TestCallback>();
             EXPECT_TRUE(
diff --git a/content/browser/indexed_db/indexed_db_blob_info.cc b/content/browser/indexed_db/indexed_db_blob_info.cc
index a2308c4..0e40f9c 100644
--- a/content/browser/indexed_db/indexed_db_blob_info.cc
+++ b/content/browser/indexed_db/indexed_db_blob_info.cc
@@ -14,11 +14,12 @@
     : is_file_(false), size_(-1), key_(DatabaseMetaDataKey::kInvalidBlobKey) {
 }
 
-IndexedDBBlobInfo::IndexedDBBlobInfo(const std::string& uuid,
-                                     const base::string16& type,
-                                     int64_t size)
+IndexedDBBlobInfo::IndexedDBBlobInfo(
+    std::unique_ptr<storage::BlobDataHandle> blob_handle,
+    const base::string16& type,
+    int64_t size)
     : is_file_(false),
-      uuid_(uuid),
+      blob_handle_(*blob_handle),
       type_(type),
       size_(size),
       key_(DatabaseMetaDataKey::kInvalidBlobKey) {}
@@ -28,18 +29,18 @@
                                      int64_t key)
     : is_file_(false), type_(type), size_(size), key_(key) {}
 
-IndexedDBBlobInfo::IndexedDBBlobInfo(const std::string& uuid,
-                                     const base::FilePath& file_path,
-                                     const base::string16& file_name,
-                                     const base::string16& type)
+IndexedDBBlobInfo::IndexedDBBlobInfo(
+    std::unique_ptr<storage::BlobDataHandle> blob_handle,
+    const base::FilePath& file_path,
+    const base::string16& file_name,
+    const base::string16& type)
     : is_file_(true),
-      uuid_(uuid),
+      blob_handle_(*blob_handle),
       type_(type),
       size_(-1),
       file_name_(file_name),
       file_path_(file_path),
-      key_(DatabaseMetaDataKey::kInvalidBlobKey) {
-}
+      key_(DatabaseMetaDataKey::kInvalidBlobKey) {}
 
 IndexedDBBlobInfo::IndexedDBBlobInfo(int64_t key,
                                      const base::string16& type,
@@ -62,12 +63,6 @@
   size_ = size;
 }
 
-void IndexedDBBlobInfo::set_uuid(const std::string& uuid) {
-  DCHECK(uuid_.empty());
-  uuid_ = uuid;
-  DCHECK(!uuid_.empty());
-}
-
 void IndexedDBBlobInfo::set_file_path(const base::FilePath& file_path) {
   DCHECK(file_path_.empty());
   file_path_ = file_path;
diff --git a/content/browser/indexed_db/indexed_db_blob_info.h b/content/browser/indexed_db/indexed_db_blob_info.h
index 8b111943..2e36c081 100644
--- a/content/browser/indexed_db/indexed_db_blob_info.h
+++ b/content/browser/indexed_db/indexed_db_blob_info.h
@@ -11,8 +11,10 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
+#include "storage/browser/blob/blob_data_handle.h"
 
 namespace content {
 
@@ -22,12 +24,12 @@
   typedef base::RepeatingCallback<void(const base::FilePath&)> ReleaseCallback;
   IndexedDBBlobInfo();
   // These two are used for Blobs.
-  IndexedDBBlobInfo(const std::string& uuid,
+  IndexedDBBlobInfo(std::unique_ptr<storage::BlobDataHandle> blob_handle,
                     const base::string16& type,
                     int64_t size);
   IndexedDBBlobInfo(const base::string16& type, int64_t size, int64_t key);
   // These two are used for Files.
-  IndexedDBBlobInfo(const std::string& uuid,
+  IndexedDBBlobInfo(std::unique_ptr<storage::BlobDataHandle> blob_handle,
                     const base::FilePath& file_path,
                     const base::string16& file_name,
                     const base::string16& type);
@@ -40,7 +42,9 @@
   IndexedDBBlobInfo& operator=(const IndexedDBBlobInfo& other);
 
   bool is_file() const { return is_file_; }
-  const std::string& uuid() const { return uuid_; }
+  const storage::BlobDataHandle* blob_handle() const {
+    return blob_handle_.has_value() ? &blob_handle_.value() : nullptr;
+  }
   const base::string16& type() const { return type_; }
   int64_t size() const { return size_; }
   const base::string16& file_name() const { return file_name_; }
@@ -53,7 +57,6 @@
   const ReleaseCallback& release_callback() const { return release_callback_; }
 
   void set_size(int64_t size);
-  void set_uuid(const std::string& uuid);
   void set_file_path(const base::FilePath& file_path);
   void set_last_modified(const base::Time& time);
   void set_key(int64_t key);
@@ -62,7 +65,8 @@
 
  private:
   bool is_file_;
-  std::string uuid_;          // Always for Blob; sometimes for File.
+  base::Optional<storage::BlobDataHandle>
+      blob_handle_;           // Always for Blob; sometimes for File.
   base::string16 type_;       // Mime type.
   int64_t size_;              // -1 if unknown for File.
   base::string16 file_name_;  // Only for File.
diff --git a/content/browser/indexed_db/indexed_db_callbacks.cc b/content/browser/indexed_db/indexed_db_callbacks.cc
index 8e16c5d..3038de8e 100644
--- a/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -738,10 +738,9 @@
 IndexedDBCallbacks::IOThreadHelper::CreateBlobData(
     const IndexedDBBlobInfo& blob_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (!blob_info.uuid().empty()) {
+  if (blob_info.blob_handle()) {
     // We're sending back a live blob, not a reference into our backing store.
-    return dispatcher_host_->blob_storage_context()->GetBlobDataFromUUID(
-        blob_info.uuid());
+    return std::make_unique<storage::BlobDataHandle>(*blob_info.blob_handle());
   }
   scoped_refptr<ShareableFileReference> shareable_file =
       ShareableFileReference::Get(blob_info.file_path());
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 3baba4f2..7d16b23 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -1216,7 +1216,6 @@
   PutOperationParams() {}
   int64_t object_store_id;
   IndexedDBValue value;
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
   std::unique_ptr<IndexedDBKey> key;
   blink::WebIDBPutMode put_mode;
   scoped_refptr<IndexedDBCallbacks> callbacks;
@@ -1230,7 +1229,6 @@
     IndexedDBTransaction* transaction,
     int64_t object_store_id,
     IndexedDBValue* value,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
     std::unique_ptr<IndexedDBKey> key,
     blink::WebIDBPutMode put_mode,
     scoped_refptr<IndexedDBCallbacks> callbacks,
@@ -1248,7 +1246,6 @@
       std::make_unique<PutOperationParams>());
   params->object_store_id = object_store_id;
   params->value.swap(*value);
-  params->handles.swap(*handles);
   params->key = std::move(key);
   params->put_mode = put_mode;
   params->callbacks = callbacks;
@@ -1336,7 +1333,7 @@
   // transaction in case of error.
   s = backing_store_->PutRecord(transaction->BackingStoreTransaction(), id(),
                                 params->object_store_id, *key, &params->value,
-                                &params->handles, &record_identifier);
+                                &record_identifier);
   if (!s.ok())
     return s;
 
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h
index 0fc4f636..a3c8f43 100644
--- a/content/browser/indexed_db/indexed_db_database.h
+++ b/content/browser/indexed_db/indexed_db_database.h
@@ -167,7 +167,6 @@
   void Put(IndexedDBTransaction* transaction,
            int64_t object_store_id,
            IndexedDBValue* value,
-           std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
            std::unique_ptr<IndexedDBKey> key,
            blink::WebIDBPutMode mode,
            scoped_refptr<IndexedDBCallbacks> callbacks,
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index fd5e264..69ac503 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -451,12 +451,11 @@
 
   // Put is asynchronous
   IndexedDBValue value("value1", std::vector<IndexedDBBlobInfo>());
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
   std::unique_ptr<IndexedDBKey> key(std::make_unique<IndexedDBKey>("key"));
   std::vector<IndexedDBIndexKeys> index_keys;
   scoped_refptr<MockIndexedDBCallbacks> request(
       new MockIndexedDBCallbacks(false));
-  db_->Put(transaction_, store_id, &value, &handles, std::move(key),
+  db_->Put(transaction_, store_id, &value, std::move(key),
            blink::kWebIDBPutModeAddOnly, request, index_keys);
 
   // Deletion is asynchronous.
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
index 46b713f..9890819 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -41,7 +41,6 @@
     int64_t object_store_id,
     const IndexedDBKey& key,
     IndexedDBValue* value,
-    std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
     RecordIdentifier* record) {
   return leveldb::Status::OK();
 }
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.h b/content/browser/indexed_db/indexed_db_fake_backing_store.h
index 42ab318..091108d 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.h
@@ -34,7 +34,6 @@
       int64_t object_store_id,
       const IndexedDBKey& key,
       IndexedDBValue* value,
-      std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
       RecordIdentifier* record) override;
 
   leveldb::Status ClearObjectStore(Transaction*,
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index 8f9321e..8c76962d 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -210,6 +210,7 @@
 
   UpdateVideoLock();
 
+  // TODO(872066): check for |pip_player_| fully matching paused player.
   if (!web_contents()->IsBeingDestroyed() && pip_player_.has_value() &&
       pip_player_->render_frame_host == render_frame_host) {
     PictureInPictureWindowControllerImpl* pip_controller =
@@ -265,6 +266,7 @@
     return;
   }
 
+  // TODO(872066): check for |pip_player_| fully matching paused player.
   if (!web_contents()->IsBeingDestroyed() && pip_player_.has_value() &&
       pip_player_->render_frame_host == render_frame_host) {
     PictureInPictureWindowControllerImpl* pip_controller =
diff --git a/content/browser/network_service_instance.cc b/content/browser/network_service_instance.cc
index 45ec9ffc..95c2be4 100644
--- a/content/browser/network_service_instance.cc
+++ b/content/browser/network_service_instance.cc
@@ -13,6 +13,7 @@
 #include "net/log/net_log_util.h"
 #include "services/network/network_service.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -21,6 +22,7 @@
 namespace {
 
 network::mojom::NetworkServicePtr* g_network_service_ptr = nullptr;
+network::NetworkConnectionTracker* g_network_connection_tracker;
 network::NetworkService* g_network_service;
 
 void CreateNetworkServiceOnIO(network::mojom::NetworkServiceRequest request) {
@@ -104,4 +106,18 @@
     g_network_service_ptr->FlushForTesting();
 }
 
+network::NetworkConnectionTracker* GetNetworkConnectionTracker() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!g_network_connection_tracker) {
+    g_network_connection_tracker = new network::NetworkConnectionTracker(
+        base::BindRepeating(&GetNetworkService));
+  }
+  return g_network_connection_tracker;
+}
+
+void SetNetworkConnectionTrackerForTesting(
+    network::NetworkConnectionTracker* network_connection_tracker) {
+  g_network_connection_tracker = network_connection_tracker;
+}
+
 }  // namespace content
diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc
index 75ccdf0..965cfcb 100644
--- a/content/browser/permissions/permission_controller_impl.cc
+++ b/content/browser/permissions/permission_controller_impl.cc
@@ -101,15 +101,15 @@
 
 int PermissionControllerImpl::SubscribePermissionStatusChange(
     PermissionType permission,
+    RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   PermissionControllerDelegate* delegate =
       browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return kNoPendingOperation;
   return delegate->SubscribePermissionStatusChange(
-      permission, requesting_origin, embedding_origin, callback);
+      permission, render_frame_host, requesting_origin, callback);
 }
 
 void PermissionControllerImpl::UnsubscribePermissionStatusChange(
diff --git a/content/browser/permissions/permission_controller_impl.h b/content/browser/permissions/permission_controller_impl.h
index 460f0335..3b9de91 100644
--- a/content/browser/permissions/permission_controller_impl.h
+++ b/content/browser/permissions/permission_controller_impl.h
@@ -55,8 +55,8 @@
 
   int SubscribePermissionStatusChange(
       PermissionType permission,
+      RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback);
 
   void UnsubscribePermissionStatusChange(int subscription_id);
diff --git a/content/browser/permissions/permission_service_context.cc b/content/browser/permissions/permission_service_context.cc
index 05cd21b..e644dd0 100644
--- a/content/browser/permissions/permission_service_context.cc
+++ b/content/browser/permissions/permission_service_context.cc
@@ -97,15 +97,10 @@
   auto subscription =
       std::make_unique<PermissionSubscription>(this, std::move(observer));
   GURL requesting_origin(origin.Serialize());
-  GURL embedding_origin = GetEmbeddingOrigin();
   int subscription_id =
       PermissionControllerImpl::FromBrowserContext(browser_context)
           ->SubscribePermissionStatusChange(
-              permission_type, requesting_origin,
-              // If the embedding_origin is empty, we'll use the |origin|
-              // instead.
-              embedding_origin.is_empty() ? requesting_origin
-                                          : embedding_origin,
+              permission_type, render_frame_host_, requesting_origin,
               base::Bind(&PermissionSubscription::OnPermissionStatusChanged,
                          base::Unretained(subscription.get())));
   subscription->set_id(subscription_id);
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index b97d2ad..7f18562 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -158,6 +158,8 @@
     return;
   }
 
+  DCHECK(media_player_id_.has_value());
+
   window_->SetPlaybackState(is_playing ? OverlayWindow::PlaybackState::kPlaying
                                        : OverlayWindow::PlaybackState::kPaused);
 }
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc
index 128a4703..7447a68 100644
--- a/content/browser/renderer_host/input/fling_controller_unittest.cc
+++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -195,7 +195,8 @@
   EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
 }
 
-TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_F(FlingControllerTest, DISABLED_ControllerHandlesTouchscreenGestureFling) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
                      gfx::Vector2dF(1000, 0));
@@ -221,7 +222,9 @@
   EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
 }
 
-TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_F(FlingControllerTest,
+       DISABLED_ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
   base::TimeTicks progress_time = base::TimeTicks::Now();
   SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0));
   EXPECT_TRUE(FlingInProgress());
diff --git a/content/browser/renderer_host/input/touch_action_filter.cc b/content/browser/renderer_host/input/touch_action_filter.cc
index 3a3ddba..658171df8 100644
--- a/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/content/browser/renderer_host/input/touch_action_filter.cc
@@ -6,6 +6,7 @@
 
 #include <math.h>
 
+#include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
@@ -42,7 +43,7 @@
       force_enable_zoom_(false) {}
 
 TouchActionFilter::~TouchActionFilter() {
-  function_call_sequence_.clear();
+  gesture_sequence_.clear();
 }
 
 FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
@@ -56,6 +57,7 @@
     case WebInputEvent::kGestureScrollBegin: {
       DCHECK(!suppress_manipulation_events_);
       DCHECK(!touchscreen_scroll_in_progress_);
+      gesture_sequence_.append("GSB ");
       touchscreen_scroll_in_progress_ = true;
       // TODO(https://crbug.com/851644): Make sure the value is properly set.
       if (!scrolling_touch_action_.has_value())
@@ -101,7 +103,7 @@
       break;
 
     case WebInputEvent::kGestureScrollEnd:
-      function_call_sequence_.clear();
+      gesture_sequence_.clear();
       DCHECK(touchscreen_scroll_in_progress_);
       touchscreen_scroll_in_progress_ = false;
       ReportGestureEventFiltered(suppress_manipulation_events_);
@@ -154,17 +156,10 @@
       scrolling_touch_action_ = allowed_touch_action_;
       // TODO(https://crbug.com/851644): Make sure the value is properly set.
       if (!scrolling_touch_action_.has_value()) {
-        auto index_of_set =
-            std::find(std::begin(function_call_sequence_),
-                      std::end(function_call_sequence_), kOnSetTouchActionCall);
-        auto index_of_reset =
-            std::find(std::begin(function_call_sequence_),
-                      std::end(function_call_sequence_), kResetTouchActionCall);
-        if (index_of_set != std::end(function_call_sequence_) &&
-            index_of_reset != std::end(function_call_sequence_) &&
-            index_of_reset > index_of_set) {
-          base::debug::DumpWithoutCrashing();
-        }
+        static auto* crash_key = base::debug::AllocateCrashKeyString(
+            "touchaction-gestures", base::debug::CrashKeySize::Size256);
+        base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
+        base::debug::DumpWithoutCrashing();
         SetTouchAction(cc::kTouchActionAuto);
       }
       DCHECK(!drop_current_tap_ending_event_);
@@ -194,7 +189,7 @@
 
 void TouchActionFilter::OnSetTouchAction(cc::TouchAction touch_action) {
   if (touch_action != cc::kTouchActionAuto)
-    function_call_sequence_.push_back(kOnSetTouchActionCall);
+    gesture_sequence_.append("Set ");
   // TODO(https://crbug.com/849819): add a DCHECK for
   // |has_touch_event_handler_|.
   // For multiple fingers, we take the intersection of the touch actions for
@@ -253,7 +248,7 @@
   // their begin event(s) suppressed will be suppressed until the next
   // sequenceo.
   if (has_touch_event_handler_) {
-    function_call_sequence_.push_back(kResetTouchActionCall);
+    gesture_sequence_.append("Reset ");
     allowed_touch_action_.reset();
     white_listed_touch_action_.reset();
   } else {
diff --git a/content/browser/renderer_host/input/touch_action_filter.h b/content/browser/renderer_host/input/touch_action_filter.h
index fa07dbe3..5b8b0e5 100644
--- a/content/browser/renderer_host/input/touch_action_filter.h
+++ b/content/browser/renderer_host/input/touch_action_filter.h
@@ -113,14 +113,7 @@
   // Whitelisted touch action received from the compositor.
   base::Optional<cc::TouchAction> white_listed_touch_action_;
 
-  // DEBUG ONLY! Record the sequence of function calls, cleared at GSE. When it
-  // is GSB and |scrolling_touch_action_| has no value, check this sequence.
-  enum FunctionCalls {
-    kOnSetTouchActionCall,
-    kResetTouchActionCall,
-  };
-
-  std::vector<FunctionCalls> function_call_sequence_;
+  std::string gesture_sequence_;
 
   DISALLOW_COPY_AND_ASSIGN(TouchActionFilter);
 };
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 3eb5677..166816c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1391,14 +1391,16 @@
       is_keep_alive_ref_count_disabled_(false),
       route_provider_binding_(this),
       visible_clients_(0),
-      priority_({
-        blink::kLaunchingProcessIsBackgrounded, frame_depth_,
-            false /* intersects_viewport */,
-            blink::kLaunchingProcessIsBoostedForPendingView,
+      priority_(!blink::kLaunchingProcessIsBackgrounded,
+                false /* has_media_stream */,
+                frame_depth_,
+                false /* intersects_viewport */,
+                blink::kLaunchingProcessIsBoostedForPendingView
 #if defined(OS_ANDROID)
-            ChildProcessImportance::NORMAL,
+                ,
+                ChildProcessImportance::NORMAL
 #endif
-      }),
+                ),
       id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
       browser_context_(browser_context),
       storage_partition_impl_(storage_partition_impl),
@@ -1847,8 +1849,7 @@
   AddFilter(new PepperRendererConnection(GetID()));
 #endif
   AddFilter(new FileAPIMessageFilter(
-      GetID(), storage_partition_impl_->GetURLRequestContext(),
-      storage_partition_impl_->GetFileSystemContext(),
+      GetID(), storage_partition_impl_->GetFileSystemContext(),
       blob_storage_context.get()));
   AddFilter(new BlobDispatcherHost(GetID(), blob_storage_context));
 #if defined(OS_MACOSX)
@@ -2198,7 +2199,7 @@
 }
 
 bool RenderProcessHostImpl::IsProcessBackgrounded() const {
-  return priority_.background;
+  return priority_.is_background();
 }
 
 void RenderProcessHostImpl::IncrementKeepAliveRefCount(
@@ -4112,36 +4113,35 @@
 void RenderProcessHostImpl::UpdateProcessPriority() {
   if (!run_renderer_in_process() && (!child_process_launcher_.get() ||
                                      child_process_launcher_->IsStarting())) {
-    priority_.background = blink::kLaunchingProcessIsBackgrounded;
+    priority_.foreground = !blink::kLaunchingProcessIsBackgrounded;
     priority_.boost_for_pending_views =
         blink::kLaunchingProcessIsBoostedForPendingView;
     return;
   }
 
-  const ChildProcessLauncherPriority priority = {
-    // We background a process as soon as it hosts no active audio/video streams
-    // and no visible widgets -- the callers must call this function whenever we
-    // transition in/out of those states.
-    visible_clients_ == 0 && media_stream_count_ == 0 &&
-        !base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableRendererBackgrounding),
-    frame_depth_,
-    intersects_viewport_,
-    // boost_for_pending_views
-    !!pending_views_,
+  const ChildProcessLauncherPriority priority(
+      // We consider a process in foreground if it hosts no visible widgets --
+      // the callers must call this function whenever we transition in/out of
+      // those states.
+      visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch(
+                                  switches::kDisableRendererBackgrounding),
+      media_stream_count_ > 0, frame_depth_, intersects_viewport_,
+      // boost_for_pending_views
+      !!pending_views_
 #if defined(OS_ANDROID)
-    GetEffectiveImportance(),
+      ,
+      GetEffectiveImportance()
 #endif
-  };
+          );
 
   const bool should_background_changed =
-      priority_.background != priority.background;
+      priority_.is_background() != priority.is_background();
   if (priority_ == priority)
     return;
 
   TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority",
-               "should_background", priority.background, "has_pending_views",
-               priority.boost_for_pending_views);
+               "should_background", priority.is_background(),
+               "has_pending_views", priority.boost_for_pending_views);
   priority_ = priority;
 
 #if defined(OS_WIN)
@@ -4170,7 +4170,7 @@
   // |priority_.boost_for_pending_views| state is not sent to renderer simply
   // due to lack of need.
   if (should_background_changed) {
-    GetRendererInterface()->SetProcessBackgrounded(priority.background);
+    GetRendererInterface()->SetProcessBackgrounded(priority.is_background());
   }
 }
 
@@ -4184,7 +4184,8 @@
 
   if (child_process_launcher_) {
     DCHECK(child_process_launcher_->GetProcess().IsValid());
-    DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded, priority_.background);
+    DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded,
+              priority_.is_background());
 
     // Unpause the channel now that the process is launched. We don't flush it
     // yet to ensure that any initialization messages sent here (e.g., things
@@ -4197,20 +4198,21 @@
           child_process_launcher_->GetProcess().Handle());
     }
 
-    // Not all platforms launch processes in the same backgrounded state. Make
-    // sure |priority_.background| reflects this platform's initial process
-    // state.
+// Not all platforms launch processes in the same backgrounded state. Make
+// sure |priority_.foreground| reflects this platform's initial process
+// state.
 #if defined(OS_MACOSX)
-    priority_.background =
-        child_process_launcher_->GetProcess().IsProcessBackgrounded(
+    priority_.foreground =
+        !child_process_launcher_->GetProcess().IsProcessBackgrounded(
             MachBroker::GetInstance());
 #elif defined(OS_ANDROID)
     // Android child process priority works differently and cannot be queried
     // directly from base::Process.
-    DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded, priority_.background);
+    DCHECK_EQ(blink::kLaunchingProcessIsBackgrounded,
+              priority_.is_background());
 #else
-    priority_.background =
-        child_process_launcher_->GetProcess().IsProcessBackgrounded();
+    priority_.foreground =
+        !child_process_launcher_->GetProcess().IsProcessBackgrounded();
 #endif  // defined(OS_MACOSX)
 
     // Disable updating process priority on startup on desktop platforms for now
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index b0ab486..ab15474 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -46,61 +46,6 @@
 
 namespace {
 
-// This class wraps a mojo::AssociatedInterfacePtr<URLLoader>. It also is a
-// URLLoader implementation and delegates URLLoader calls to the wrapped loader.
-class DelegatingURLLoader final : public network::mojom::URLLoader {
- public:
-  explicit DelegatingURLLoader(network::mojom::URLLoaderPtr loader)
-      : binding_(this), loader_(std::move(loader)) {}
-  ~DelegatingURLLoader() override {}
-
-  void FollowRedirect(const base::Optional<std::vector<std::string>>&
-                          to_be_removed_request_headers,
-                      const base::Optional<net::HttpRequestHeaders>&
-                          modified_request_headers) override {
-    DCHECK(!modified_request_headers.has_value())
-        << "Redirect with modified headers was not supported yet. "
-           "crbug.com/845683";
-    loader_->FollowRedirect(base::nullopt, base::nullopt);
-  }
-  void ProceedWithResponse() override { NOTREACHED(); }
-
-  void SetPriority(net::RequestPriority priority,
-                   int intra_priority_value) override {
-    loader_->SetPriority(priority, intra_priority_value);
-  }
-
-  void PauseReadingBodyFromNet() override {
-    loader_->PauseReadingBodyFromNet();
-  }
-  void ResumeReadingBodyFromNet() override {
-    loader_->ResumeReadingBodyFromNet();
-  }
-
-  network::mojom::URLLoaderPtr CreateInterfacePtrAndBind() {
-    network::mojom::URLLoaderPtr loader;
-    binding_.Bind(mojo::MakeRequest(&loader));
-    // This unretained pointer is safe, because |binding_| is owned by |this|
-    // and the callback will never be called after |this| is destroyed.
-    binding_.set_connection_error_handler(
-        base::BindOnce(&DelegatingURLLoader::Cancel, base::Unretained(this)));
-    return loader;
-  }
-
- private:
-  // Called when the network::mojom::URLLoaderPtr in the service worker is
-  // deleted.
-  void Cancel() {
-    // Cancel loading as stated in url_loader.mojom.
-    loader_ = nullptr;
-  }
-
-  mojo::Binding<network::mojom::URLLoader> binding_;
-  network::mojom::URLLoaderPtr loader_;
-
-  DISALLOW_COPY_AND_ASSIGN(DelegatingURLLoader);
-};
-
 void NotifyNavigationPreloadRequestSentOnUI(
     const network::ResourceRequest& request,
     const std::pair<int, int>& worker_id,
@@ -441,10 +386,8 @@
  public:
   URLLoaderAssets(
       std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory,
-      std::unique_ptr<network::mojom::URLLoader> url_loader,
       std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
       : url_loader_factory_(std::move(url_loader_factory)),
-        url_loader_(std::move(url_loader)),
         url_loader_client_(std::move(url_loader_client)) {}
 
   void MaybeReportToDevTools(std::pair<int, int> worker_id,
@@ -457,7 +400,6 @@
   virtual ~URLLoaderAssets() {}
 
   std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;
-  std::unique_ptr<network::mojom::URLLoader> url_loader_;
   std::unique_ptr<DelegatingURLLoaderClient> url_loader_client_;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderAssets);
@@ -721,30 +663,26 @@
   DCHECK_LT(request_id, -1);
 
   preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
-  network::mojom::URLLoaderClientPtr url_loader_client_ptr;
+  network::mojom::URLLoaderClientPtr inner_url_loader_client;
   preload_handle_->url_loader_client_request =
-      mojo::MakeRequest(&url_loader_client_ptr);
+      mojo::MakeRequest(&inner_url_loader_client);
   auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
-      std::move(url_loader_client_ptr), std::move(on_response), request);
-  network::mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
-  url_loader_client->Bind(&url_loader_client_ptr_to_pass);
-  network::mojom::URLLoaderPtr url_loader_associated_ptr;
+      std::move(inner_url_loader_client), std::move(on_response), request);
+  network::mojom::URLLoaderClientPtr url_loader_client_to_pass;
+  url_loader_client->Bind(&url_loader_client_to_pass);
+  network::mojom::URLLoaderPtr url_loader;
 
   url_loader_factory->CreateLoaderAndStart(
-      mojo::MakeRequest(&url_loader_associated_ptr),
-      original_info->GetRouteID(), request_id,
+      mojo::MakeRequest(&url_loader), original_info->GetRouteID(), request_id,
       network::mojom::kURLLoadOptionNone, request,
-      std::move(url_loader_client_ptr_to_pass),
+      std::move(url_loader_client_to_pass),
       net::MutableNetworkTrafficAnnotationTag(
           original_request->traffic_annotation()));
 
-  auto url_loader = std::make_unique<DelegatingURLLoader>(
-      std::move(url_loader_associated_ptr));
-  preload_handle_->url_loader =
-      url_loader->CreateInterfacePtrAndBind().PassInterface();
+  preload_handle_->url_loader = url_loader.PassInterface();
+
   url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
-      std::move(url_loader_factory), std::move(url_loader),
-      std::move(url_loader_client));
+      std::move(url_loader_factory), std::move(url_loader_client));
   return true;
 }
 
@@ -784,40 +722,33 @@
 
   // Create the DelegatingURLLoaderClient, which becomes the
   // URLLoaderClient for the navigation preload network request.
-  network::mojom::URLLoaderClientPtr url_loader_client_ptr;
+  network::mojom::URLLoaderClientPtr inner_url_loader_client;
   preload_handle_->url_loader_client_request =
-      mojo::MakeRequest(&url_loader_client_ptr);
+      mojo::MakeRequest(&inner_url_loader_client);
   auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
-      std::move(url_loader_client_ptr), std::move(on_response),
+      std::move(inner_url_loader_client), std::move(on_response),
       resource_request);
 
   // Start the network request for the URL using the network loader.
   // TODO(falken): What to do about routing_id, request_id?
-  network::mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
-  url_loader_client->Bind(&url_loader_client_ptr_to_pass);
-  network::mojom::URLLoaderPtr url_loader_associated_ptr;
+  network::mojom::URLLoaderClientPtr url_loader_client_to_pass;
+  url_loader_client->Bind(&url_loader_client_to_pass);
+  network::mojom::URLLoaderPtr url_loader;
   url_loader_factory_getter->GetNetworkFactory()->CreateLoaderAndStart(
-      mojo::MakeRequest(&url_loader_associated_ptr), -1 /* routing_id? */,
+      mojo::MakeRequest(&url_loader), -1 /* routing_id? */,
       -1 /* request_id? */, network::mojom::kURLLoadOptionNone,
-      resource_request, std::move(url_loader_client_ptr_to_pass),
+      resource_request, std::move(url_loader_client_to_pass),
       net::MutableNetworkTrafficAnnotationTag(
           kNavigationPreloadTrafficAnnotation));
 
-  // Hook the load up to DelegatingURLLoader, which will call our
-  // DelegatingURLLoaderClient.
-  auto url_loader = std::make_unique<DelegatingURLLoader>(
-      std::move(url_loader_associated_ptr));
-  preload_handle_->url_loader =
-      url_loader->CreateInterfacePtrAndBind().PassInterface();
+  preload_handle_->url_loader = url_loader.PassInterface();
 
   DCHECK(!url_loader_assets_);
   // Unlike the non-S13N code path, we don't own the URLLoaderFactory being used
   // (it's the generic network factory), so we don't need to pass it to
   // URLLoaderAssets to keep it alive.
-  std::unique_ptr<network::mojom::URLLoaderFactory> null_factory;
   url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
-      std::move(null_factory), std::move(url_loader),
-      std::move(url_loader_client));
+      nullptr /* url_loader_factory */, std::move(url_loader_client));
   return true;
 }
 
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 3184042..192a0af 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -164,20 +164,13 @@
 
   // Add the network factory to the bundle to pass to the renderer. The bundle
   // is only provided (along with |script_loader_factory|) if
-  // NetworkService/S13nSW is enabled.
+  // NetworkService/S13nServiceWorker is enabled, and default factory isn't
+  // provided if NetworkService is on but S13nServiceWorker is off.
   DCHECK(!script_loader_factory || factory_bundle);
-  if (factory_bundle) {
+  if (factory_bundle && !factory_bundle->default_factory_info()) {
+    DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
     network::mojom::URLLoaderFactoryPtrInfo network_factory_info;
-    if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-      // NetworkService is on: Use the network service.
-      CreateNetworkFactory(mojo::MakeRequest(&network_factory_info));
-    } else {
-      // NetworkService is off: RenderProcessHost gives us a non-NetworkService
-      // network factory.
-      RenderProcessHost::FromID(process_id_)
-          ->CreateURLLoaderFactory(mojo::MakeRequest(&network_factory_info));
-    }
-    DCHECK(!factory_bundle->default_factory_info());
+    CreateNetworkFactory(mojo::MakeRequest(&network_factory_info));
     factory_bundle->default_factory_info() = std::move(network_factory_info);
 
     // TODO(falken): We might need to set the default factory to AppCache
diff --git a/content/browser/shared_worker/shared_worker_script_loader.cc b/content/browser/shared_worker/shared_worker_script_loader.cc
index d363f74..2927380 100644
--- a/content/browser/shared_worker/shared_worker_script_loader.cc
+++ b/content/browser/shared_worker/shared_worker_script_loader.cc
@@ -6,6 +6,7 @@
 
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/loader/navigation_loader_interceptor.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/public/browser/resource_context.h"
 #include "net/url_request/redirect_util.h"
@@ -15,6 +16,7 @@
 namespace content {
 
 SharedWorkerScriptLoader::SharedWorkerScriptLoader(
+    int process_id,
     int32_t routing_id,
     int32_t request_id,
     uint32_t options,
@@ -25,7 +27,8 @@
     ResourceContext* resource_context,
     scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
-    : routing_id_(routing_id),
+    : process_id_(process_id),
+      routing_id_(routing_id),
       request_id_(request_id),
       options_(options),
       resource_request_(resource_request),
@@ -143,6 +146,12 @@
   interceptor_index_ = 0;
   url_loader_client_binding_.Unbind();
   redirect_info_.reset();
+
+  // Cancel the request on ResourceDispatcherHost so that we can fall back
+  // to network again.
+  DCHECK(ResourceDispatcherHostImpl::Get());
+  ResourceDispatcherHostImpl::Get()->CancelRequest(process_id_, request_id_);
+
   Start();
 }
 
diff --git a/content/browser/shared_worker/shared_worker_script_loader.h b/content/browser/shared_worker/shared_worker_script_loader.h
index 4730433..cd3d6d5 100644
--- a/content/browser/shared_worker/shared_worker_script_loader.h
+++ b/content/browser/shared_worker/shared_worker_script_loader.h
@@ -43,6 +43,7 @@
   // non-NetworkService factories used for non-http(s) URLs, e.g., a
   // chrome-extension:// URL.
   SharedWorkerScriptLoader(
+      int process_id,
       int32_t routing_id,
       int32_t request_id,
       uint32_t options,
@@ -93,6 +94,7 @@
   std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
   size_t interceptor_index_ = 0;
 
+  const int process_id_;
   const int32_t routing_id_;
   const int32_t request_id_;
   const uint32_t options_;
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.cc b/content/browser/shared_worker/shared_worker_script_loader_factory.cc
index c4a876b..74eaef6 100644
--- a/content/browser/shared_worker/shared_worker_script_loader_factory.cc
+++ b/content/browser/shared_worker/shared_worker_script_loader_factory.cc
@@ -20,12 +20,14 @@
 namespace content {
 
 SharedWorkerScriptLoaderFactory::SharedWorkerScriptLoaderFactory(
+    int process_id,
     ServiceWorkerContextWrapper* context,
     base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
     base::WeakPtr<AppCacheHost> appcache_host,
     ResourceContext* resource_context,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
-    : service_worker_provider_host_(std::move(service_worker_provider_host)),
+    : process_id_(process_id),
+      service_worker_provider_host_(std::move(service_worker_provider_host)),
       appcache_host_(std::move(appcache_host)),
       resource_context_(resource_context),
       loader_factory_(std::move(loader_factory)) {
@@ -61,9 +63,9 @@
   // Create a SharedWorkerScriptLoader to load the script.
   mojo::MakeStrongBinding(
       std::make_unique<SharedWorkerScriptLoader>(
-          routing_id, request_id, options, resource_request, std::move(client),
-          service_worker_provider_host_, appcache_host_, resource_context_,
-          loader_factory_, traffic_annotation),
+          process_id_, routing_id, request_id, options, resource_request,
+          std::move(client), service_worker_provider_host_, appcache_host_,
+          resource_context_, loader_factory_, traffic_annotation),
       std::move(request));
 }
 
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.h b/content/browser/shared_worker/shared_worker_script_loader_factory.h
index 356baea..f54949b 100644
--- a/content/browser/shared_worker/shared_worker_script_loader_factory.h
+++ b/content/browser/shared_worker/shared_worker_script_loader_factory.h
@@ -37,6 +37,7 @@
   // the NetworkService. However, it may internally contain non-NetworkService
   // factories used for non-http(s) URLs, e.g., a chrome-extension:// URL.
   SharedWorkerScriptLoaderFactory(
+      int process_id,
       ServiceWorkerContextWrapper* context,
       base::WeakPtr<ServiceWorkerProviderHost> provider_host,
       base::WeakPtr<AppCacheHost> appcache_host,
@@ -56,6 +57,7 @@
   void Clone(network::mojom::URLLoaderFactoryRequest request) override;
 
  private:
+  const int process_id_;
   base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
   base::WeakPtr<AppCacheHost> appcache_host_;
   ResourceContext* resource_context_ = nullptr;
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc
index 1defce7..9ed1be7 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -83,6 +83,17 @@
     factory_bundle->factories_info().emplace(url::kFileScheme,
                                              file_factory_ptr.PassInterface());
   }
+
+  // Use RenderProcessHost's network factory as the default factory if
+  // NetworkService is off. If NetworkService is on the default factory is
+  // set in CreateScriptLoaderOnIO().
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    network::mojom::URLLoaderFactoryPtr default_factory;
+    RenderProcessHost::FromID(process_id)
+        ->CreateURLLoaderFactory(mojo::MakeRequest(&default_factory));
+    factory_bundle->default_factory_info() = default_factory.PassInterface();
+  }
+
   return factory_bundle;
 }
 
@@ -116,20 +127,25 @@
     url_loader_factory = network::SharedURLLoaderFactory::Create(
         std::move(blob_url_loader_factory_info));
   } else {
+    // Add the network factory to the bundle. If NetworkService is off the
+    // default factory was already set in CreateFactoryBundle().
+    DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService) ||
+           factory_bundle_for_browser_info->default_factory_info());
     // Create a factory bundle to use.
     scoped_refptr<URLLoaderFactoryBundle> factory_bundle =
         base::MakeRefCounted<URLLoaderFactoryBundle>(
             std::move(factory_bundle_for_browser_info));
     url_loader_factory = factory_bundle;
 
-    // Add the network factory to the bundle. The factory from
-    // CloneNetworkFactory() doesn't support reconnection to the network service
-    // after a crash, but it's OK since it's used for a single shared worker
-    // startup.
-    network::mojom::URLLoaderFactoryPtr network_factory_ptr;
-    loader_factory_getter->CloneNetworkFactory(
-        mojo::MakeRequest(&network_factory_ptr));
-    factory_bundle->SetDefaultFactory(std::move(network_factory_ptr));
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+      // The factory from CloneNetworkFactory() doesn't support reconnection to
+      // the network service after a crash, but it's OK since it's used for a
+      // single shared worker startup.
+      network::mojom::URLLoaderFactoryPtr network_factory_ptr;
+      loader_factory_getter->CloneNetworkFactory(
+          mojo::MakeRequest(&network_factory_ptr));
+      factory_bundle->SetDefaultFactory(std::move(network_factory_ptr));
+    }
   }
 
   // It's safe for |appcache_handle_core| to be a raw pointer. The core is owned
@@ -144,8 +160,9 @@
   network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory;
   mojo::MakeStrongAssociatedBinding(
       std::make_unique<SharedWorkerScriptLoaderFactory>(
-          context.get(), host->AsWeakPtr(), std::move(appcache_host),
-          context->resource_context(), std::move(url_loader_factory)),
+          process_id, context.get(), host->AsWeakPtr(),
+          std::move(appcache_host), context->resource_context(),
+          std::move(url_loader_factory)),
       mojo::MakeRequest(&script_loader_factory));
 
   // We continue in StartWorker.
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 4d758960..3d07ce8e0 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -291,6 +291,33 @@
                                          gfx::PointF(95, 95));
 }
 
+void NonFlatTransformedSurfaceHitTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_non_flat_transformed_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
+                                         gfx::PointF(5, 5), rwhv_child,
+                                         gfx::PointF(5, 5));
+}
+
 // Helper function that performs a surface hittest in nested frame.
 void NestedSurfaceHitTestTestHelper(
     Shell* shell,
@@ -1834,6 +1861,16 @@
   NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
 }
 
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+                       NonFlatTransformedSurfaceHitTestTest) {
+  NonFlatTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
+                       NonFlatTransformedSurfaceHitTestTest) {
+  NonFlatTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
 #if defined(OS_LINUX)
 // Flaky timeouts and failures: https://crbug.com/833380
 #define MAYBE_OverlapSurfaceHitTestTest DISABLED_OverlapSurfaceHitTestTest
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
index 8b23dd6a..67d5588 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -435,7 +435,7 @@
     }
 
     @CalledByNative
-    private void setPriority(int pid, boolean foreground, long frameDepth,
+    private void setPriority(int pid, boolean foreground, boolean hasMediaStream, long frameDepth,
             boolean intersectsViewport, boolean boostForPendingViews,
             @ChildProcessImportance int importance) {
         assert LauncherThread.runningOnLauncherThread();
@@ -451,12 +451,17 @@
             boostForPendingViews = false;
         }
 
+        boolean mediaRendererHasModerate = ContentFeatureList.isEnabled(
+                ContentFeatureList.BACKGROUND_MEDIA_RENDERER_HAS_MODERATE_BINDING);
+
         @ChildProcessImportance
         int newEffectiveImportance;
-        if ((foreground && frameDepth == 0) || importance == ChildProcessImportance.IMPORTANT) {
+        if ((foreground && frameDepth == 0) || importance == ChildProcessImportance.IMPORTANT
+                || (hasMediaStream && !mediaRendererHasModerate)) {
             newEffectiveImportance = ChildProcessImportance.IMPORTANT;
         } else if ((foreground && frameDepth > 0 && intersectsViewport) || boostForPendingViews
-                || importance == ChildProcessImportance.MODERATE) {
+                || importance == ChildProcessImportance.MODERATE
+                || (hasMediaStream && mediaRendererHasModerate)) {
             newEffectiveImportance = ChildProcessImportance.MODERATE;
         } else {
             newEffectiveImportance = ChildProcessImportance.NORMAL;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentFeatureList.java b/content/public/android/java/src/org/chromium/content/browser/ContentFeatureList.java
index e59b7cc..2a0060a9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentFeatureList.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentFeatureList.java
@@ -33,5 +33,8 @@
     public static final String ENHANCED_SELECTION_INSERTION_HANDLE =
             "EnhancedSelectionInsertionHandle";
 
+    public static final String BACKGROUND_MEDIA_RENDERER_HAS_MODERATE_BINDING =
+            "BackgroundMediaRendererHasModerateBinding";
+
     private static native boolean nativeIsEnabled(String featureName);
 }
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 7a0734e..62eafade 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -196,7 +196,6 @@
           "device.mojom.VibrationManager",
           "device.mojom.UsbDeviceManager",
           "device.mojom.VRService",
-          "device.mojom.VRService",
           "device.mojom.WakeLock",
           "discardable_memory.mojom.DiscardableSharedMemoryManager",
           "media.mojom.ImageCapture",
diff --git a/content/public/browser/network_service_instance.h b/content/public/browser/network_service_instance.h
index 47e20afb..5f57eaaa 100644
--- a/content/public/browser/network_service_instance.h
+++ b/content/public/browser/network_service_instance.h
@@ -8,6 +8,7 @@
 #include "content/common/content_export.h"
 
 namespace network {
+class NetworkConnectionTracker;
 class NetworkService;
 namespace mojom {
 class NetworkService;
@@ -34,6 +35,17 @@
 // Must only be called on the UI thread.
 CONTENT_EXPORT void FlushNetworkServiceInstanceForTesting();
 
+// Returns a NetworkConnectionTracker that can be used to subscribe for
+// network change events.
+// Must only be called on the UI thread.
+CONTENT_EXPORT network::NetworkConnectionTracker* GetNetworkConnectionTracker();
+
+// Sets the NetworkConnectionTracker instance to use. For testing only.
+// Must be called on the UI thread. Must be called before the first call to
+// GetNetworkConnectionTracker.
+CONTENT_EXPORT void SetNetworkConnectionTrackerForTesting(
+    network::NetworkConnectionTracker* network_connection_tracker);
+
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_BROWSER_NETWORK_SERVICE_INSTANCE_H_
diff --git a/content/public/browser/permission_controller_delegate.h b/content/public/browser/permission_controller_delegate.h
index 2a81ed3..98eb6518 100644
--- a/content/public/browser/permission_controller_delegate.h
+++ b/content/public/browser/permission_controller_delegate.h
@@ -77,13 +77,13 @@
                                const GURL& embedding_origin) = 0;
 
   // Runs the given |callback| whenever the |permission| associated with the
-  // pair { requesting_origin, embedding_origin } changes.
-  // Returns the subscription_id to be used to unsubscribe. Can be
-  // kNoPendingOperation if the subscribe was not successful.
+  // given RenderFrameHost changes. A nullptr should be passed if the request
+  // is from a worker. Returns the subscription_id to be used to unsubscribe.
+  // Can be kNoPendingOperation if the subscribe was not successful.
   virtual int SubscribePermissionStatusChange(
-      PermissionType permission,
+      content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback) = 0;
 
   // Unregisters from permission status change notifications.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 6b43766d..79725fa 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -620,6 +620,12 @@
 const base::Feature kHideIncorrectlySizedFullscreenFrames{
     "HideIncorrectlySizedFullscreenFrames", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Sets moderate binding to background renderers playing media, when enabled.
+// Else the renderer will have strong binding.
+const base::Feature kBackgroundMediaRendererHasModerateBinding{
+    "BackgroundMediaRendererHasModerateBinding",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether the WebNFC API is enabled:
 // https://w3c.github.io/web-nfc/
 const base::Feature kWebNfc{"WebNFC", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 5cd76739..fbbdce2 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -140,6 +140,8 @@
 
 #if defined(OS_ANDROID)
 CONTENT_EXPORT extern const base::Feature kAndroidAutofillAccessibility;
+CONTENT_EXPORT extern const base::Feature
+    kBackgroundMediaRendererHasModerateBinding;
 CONTENT_EXPORT extern const base::Feature kDisplayCutoutAPI;
 CONTENT_EXPORT extern const base::Feature kHideIncorrectlySizedFullscreenFrames;
 CONTENT_EXPORT extern const base::Feature kWebNfc;
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 7ea6490..3107fb5 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -252,7 +252,8 @@
   return true;
 }
 
-bool ContentRendererClient::IsBackgroundMediaSuspendEnabled() {
+bool ContentRendererClient::IsBackgroundMediaSuspendEnabled(
+    RenderFrame* render_frame) {
 #if defined(OS_ANDROID)
   return true;
 #else
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 0aca5928..e76cf174 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -390,8 +390,8 @@
   virtual bool IsIdleMediaSuspendEnabled();
 
   // Whether the renderer should automatically suspend media playback on
-  // background tabs.
-  virtual bool IsBackgroundMediaSuspendEnabled();
+  // background tabs for given |render_frame|.
+  virtual bool IsBackgroundMediaSuspendEnabled(RenderFrame* render_frame);
 
   // Called when a resource at |url| is loaded using an otherwise-valid legacy
   // Symantec certificate that will be distrusted in future. Allows the embedder
diff --git a/content/public/test/OWNERS b/content/public/test/OWNERS
index 9f53b453..7b359503 100644
--- a/content/public/test/OWNERS
+++ b/content/public/test/OWNERS
@@ -6,6 +6,9 @@
 # For download tests support review.
 per-file test_download_http_response.*=file://components/download/OWNERS
 
+# For Android-specific changes.
+per-file *android*=file://content/public/test/android/OWNERS
+
 # For security presubmit checks, though test mojom really don't need review.
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/content/public/test/mock_permission_manager.cc b/content/public/test/mock_permission_manager.cc
index 9157b1b..32f1ef91 100644
--- a/content/public/test/mock_permission_manager.cc
+++ b/content/public/test/mock_permission_manager.cc
@@ -34,8 +34,8 @@
 
 int MockPermissionManager::SubscribePermissionStatusChange(
     PermissionType permission,
+    RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   // Return a fake subscription_id.
   return 0;
diff --git a/content/public/test/mock_permission_manager.h b/content/public/test/mock_permission_manager.h
index b140a499..d7da1d8 100644
--- a/content/public/test/mock_permission_manager.h
+++ b/content/public/test/mock_permission_manager.h
@@ -52,8 +52,8 @@
                        const GURL& embedding_origin) override {}
   int SubscribePermissionStatusChange(
       PermissionType permission,
+      RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override {}
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
index 839f4b8..5f0e57a 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/indexed_db/indexed_db_callbacks_impl.h"
 
-#include "base/threading/thread_task_runner_handle.h"
 #include "content/common/indexed_db/indexed_db_constants.h"
 #include "content/renderer/indexed_db/indexed_db_dispatcher.h"
 #include "content/renderer/indexed_db/indexed_db_key_builders.h"
@@ -109,10 +108,8 @@
 IndexedDBCallbacksImpl::IndexedDBCallbacksImpl(
     std::unique_ptr<WebIDBCallbacks> callbacks,
     int64_t transaction_id,
-    const base::WeakPtr<WebIDBCursorImpl>& cursor,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : callback_runner_(std::move(callback_runner)),
-      callbacks_(std::move(callbacks)),
+    const base::WeakPtr<WebIDBCursorImpl>& cursor)
+    : callbacks_(std::move(callbacks)),
       cursor_(cursor),
       transaction_id_(transaction_id) {}
 
@@ -146,8 +143,7 @@
     blink::WebIDBDataLoss data_loss,
     const std::string& data_loss_message,
     const content::IndexedDBDatabaseMetadata& metadata) {
-  WebIDBDatabase* database =
-      new WebIDBDatabaseImpl(std::move(database_info), callback_runner_);
+  WebIDBDatabase* database = new WebIDBDatabaseImpl(std::move(database_info));
   WebIDBMetadata web_metadata;
   ConvertDatabaseMetadata(metadata, &web_metadata);
   callbacks_->OnUpgradeNeeded(old_version, database, web_metadata, data_loss,
@@ -160,8 +156,7 @@
     const content::IndexedDBDatabaseMetadata& metadata) {
   WebIDBDatabase* database = nullptr;
   if (database_info.is_valid()) {
-    database =
-        new WebIDBDatabaseImpl(std::move(database_info), callback_runner_);
+    database = new WebIDBDatabaseImpl(std::move(database_info));
   }
 
   WebIDBMetadata web_metadata;
@@ -175,8 +170,8 @@
     const IndexedDBKey& key,
     const IndexedDBKey& primary_key,
     indexed_db::mojom::ValuePtr value) {
-  WebIDBCursorImpl* cursor = new WebIDBCursorImpl(
-      std::move(cursor_info), transaction_id_, callback_runner_);
+  WebIDBCursorImpl* cursor =
+      new WebIDBCursorImpl(std::move(cursor_info), transaction_id_);
   callbacks_->OnSuccess(cursor, WebIDBKeyBuilder::Build(key),
                         WebIDBKeyBuilder::Build(primary_key),
                         ConvertValue(value));
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.h b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
index 5cdcbbb..6024a4a8 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.h
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_RENDERER_INDEXED_DB_INDEXED_DB_CALLBACKS_IMPL_H_
 #define CONTENT_RENDERER_INDEXED_DB_INDEXED_DB_CALLBACKS_IMPL_H_
 
-#include "base/single_thread_task_runner.h"
 #include "content/common/indexed_db/indexed_db.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
@@ -28,11 +27,9 @@
   static blink::WebIDBValue ConvertValue(
       const indexed_db::mojom::ValuePtr& value);
 
-  IndexedDBCallbacksImpl(
-      std::unique_ptr<blink::WebIDBCallbacks> callbacks,
-      int64_t transaction_id,
-      const base::WeakPtr<WebIDBCursorImpl>& cursor,
-      scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
+  IndexedDBCallbacksImpl(std::unique_ptr<blink::WebIDBCallbacks> callbacks,
+                         int64_t transaction_id,
+                         const base::WeakPtr<WebIDBCursorImpl>& cursor);
   ~IndexedDBCallbacksImpl() override;
 
   // indexed_db::mojom::Callbacks implementation:
diff --git a/content/renderer/indexed_db/webidbcursor_impl.cc b/content/renderer/indexed_db/webidbcursor_impl.cc
index 0ee145e..9c31bf08 100644
--- a/content/renderer/indexed_db/webidbcursor_impl.cc
+++ b/content/renderer/indexed_db/webidbcursor_impl.cc
@@ -28,10 +28,8 @@
 
 WebIDBCursorImpl::WebIDBCursorImpl(
     indexed_db::mojom::CursorAssociatedPtrInfo cursor_info,
-    int64_t transaction_id,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
+    int64_t transaction_id)
     : transaction_id_(transaction_id),
-      callback_runner_(std::move(callback_runner)),
       cursor_(std::move(cursor_info)),
       continue_count_(0),
       used_prefetches_(0),
@@ -63,8 +61,7 @@
       transaction_id_, this);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr(),
-      callback_runner_);
+      std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
   cursor_->Advance(count, GetCallbacksProxy(std::move(callbacks_impl)));
 }
 
@@ -89,8 +86,7 @@
       ++pending_onsuccess_callbacks_;
 
       auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-          std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr(),
-          callback_runner_);
+          std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
       cursor_->Prefetch(prefetch_amount_,
                         GetCallbacksProxy(std::move(callbacks_impl)));
 
@@ -111,8 +107,7 @@
       transaction_id_, this);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr(),
-      callback_runner_);
+      std::move(callbacks), transaction_id_, weak_factory_.GetWeakPtr());
   cursor_->Continue(IndexedDBKeyBuilder::Build(key),
                     IndexedDBKeyBuilder::Build(primary_key),
                     GetCallbacksProxy(std::move(callbacks_impl)));
diff --git a/content/renderer/indexed_db/webidbcursor_impl.h b/content/renderer/indexed_db/webidbcursor_impl.h
index ff277dc5..f363d5dc 100644
--- a/content/renderer/indexed_db/webidbcursor_impl.h
+++ b/content/renderer/indexed_db/webidbcursor_impl.h
@@ -21,10 +21,6 @@
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace content {
 
 class IndexedDBCallbacksImpl;
@@ -32,8 +28,7 @@
 class CONTENT_EXPORT WebIDBCursorImpl : public blink::WebIDBCursor {
  public:
   WebIDBCursorImpl(indexed_db::mojom::CursorAssociatedPtrInfo cursor,
-                   int64_t transaction_id,
-                   scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
+                   int64_t transaction_id);
   ~WebIDBCursorImpl() override;
 
   void Advance(unsigned long count, blink::WebIDBCallbacks* callback) override;
@@ -71,7 +66,6 @@
 
   int64_t transaction_id_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
   indexed_db::mojom::CursorAssociatedPtr cursor_;
 
   // Prefetch cache.
diff --git a/content/renderer/indexed_db/webidbcursor_impl_unittest.cc b/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
index 071d1300..18495907 100644
--- a/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
+++ b/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
@@ -123,9 +123,7 @@
     indexed_db::mojom::CursorAssociatedPtr ptr;
     mock_cursor_ = std::make_unique<MockCursorImpl>(
         mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
-    cursor_ = std::make_unique<WebIDBCursorImpl>(
-        ptr.PassInterface(), 1,
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+    cursor_ = std::make_unique<WebIDBCursorImpl>(ptr.PassInterface(), 1);
   }
 
  protected:
diff --git a/content/renderer/indexed_db/webidbdatabase_impl.cc b/content/renderer/indexed_db/webidbdatabase_impl.cc
index e0e036e..366aa15 100644
--- a/content/renderer/indexed_db/webidbdatabase_impl.cc
+++ b/content/renderer/indexed_db/webidbdatabase_impl.cc
@@ -62,11 +62,8 @@
 
 }  // namespace
 
-WebIDBDatabaseImpl::WebIDBDatabaseImpl(
-    DatabaseAssociatedPtrInfo database_info,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : callback_runner_(std::move(callback_runner)),
-      database_(std::move(database_info)) {}
+WebIDBDatabaseImpl::WebIDBDatabaseImpl(DatabaseAssociatedPtrInfo database_info)
+    : database_(std::move(database_info)) {}
 
 WebIDBDatabaseImpl::~WebIDBDatabaseImpl() = default;
 
@@ -141,7 +138,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->Get(transaction_id, object_store_id, index_id,
                  IndexedDBKeyRangeBuilder::Build(key_range), key_only,
                  GetCallbacksProxy(std::move(callbacks_impl)));
@@ -158,7 +155,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->GetAll(transaction_id, object_store_id, index_id,
                     IndexedDBKeyRangeBuilder::Build(key_range), key_only,
                     max_count, GetCallbacksProxy(std::move(callbacks_impl)));
@@ -216,7 +213,7 @@
   }
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->Put(transaction_id, object_store_id, std::move(mojo_value), key,
                  put_mode, ConvertWebIndexKeys(index_ids, index_keys),
                  GetCallbacksProxy(std::move(callbacks_impl)));
@@ -255,7 +252,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->OpenCursor(transaction_id, object_store_id, index_id,
                         IndexedDBKeyRangeBuilder::Build(key_range), direction,
                         key_only, task_type,
@@ -271,7 +268,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->Count(transaction_id, object_store_id, index_id,
                    IndexedDBKeyRangeBuilder::Build(key_range),
                    GetCallbacksProxy(std::move(callbacks_impl)));
@@ -285,7 +282,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->DeleteRange(transaction_id, object_store_id,
                          IndexedDBKeyRangeBuilder::Build(primary_key),
                          GetCallbacksProxy(std::move(callbacks_impl)));
@@ -299,7 +296,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->DeleteRange(transaction_id, object_store_id,
                          IndexedDBKeyRangeBuilder::Build(key_range),
                          GetCallbacksProxy(std::move(callbacks_impl)));
@@ -312,7 +309,7 @@
       transaction_id, nullptr);
 
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, callback_runner_);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   database_->Clear(transaction_id, object_store_id,
                    GetCallbacksProxy(std::move(callbacks_impl)));
 }
diff --git a/content/renderer/indexed_db/webidbdatabase_impl.h b/content/renderer/indexed_db/webidbdatabase_impl.h
index d208d00e..b6e235c 100644
--- a/content/renderer/indexed_db/webidbdatabase_impl.h
+++ b/content/renderer/indexed_db/webidbdatabase_impl.h
@@ -30,9 +30,7 @@
 
 class CONTENT_EXPORT WebIDBDatabaseImpl : public blink::WebIDBDatabase {
  public:
-  WebIDBDatabaseImpl(
-      indexed_db::mojom::DatabaseAssociatedPtrInfo database,
-      scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
+  WebIDBDatabaseImpl(indexed_db::mojom::DatabaseAssociatedPtrInfo database);
   ~WebIDBDatabaseImpl() override;
 
   // blink::WebIDBDatabase
@@ -148,7 +146,6 @@
   size_t max_put_value_size_ = kMaxIDBMessageSizeInBytes;
 
   std::set<int32_t> observer_ids_;
-  scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
   indexed_db::mojom::DatabaseAssociatedPtr database_;
 };
 
diff --git a/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc b/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
index 491da74..879fd50 100644
--- a/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
+++ b/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
@@ -59,8 +59,7 @@
   StrictMock<MockWebIDBCallbacks> callbacks;
   EXPECT_CALL(callbacks, OnError(_)).Times(1);
 
-  WebIDBDatabaseImpl database_impl(
-      nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+  WebIDBDatabaseImpl database_impl(nullptr);
   database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
   const WebIDBKey idb_key = WebIDBKey::CreateNumber(0);
   database_impl.Put(transaction_id, object_store_id, value, web_blob_info,
@@ -87,8 +86,7 @@
   StrictMock<MockWebIDBCallbacks> callbacks;
   EXPECT_CALL(callbacks, OnError(_)).Times(1);
 
-  WebIDBDatabaseImpl database_impl(
-      nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+  WebIDBDatabaseImpl database_impl(nullptr);
   database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
   database_impl.Put(transaction_id, object_store_id, value, web_blob_info,
                     key.View(), blink::kWebIDBPutModeAddOrUpdate, &callbacks,
diff --git a/content/renderer/indexed_db/webidbfactory_impl.cc b/content/renderer/indexed_db/webidbfactory_impl.cc
index 403596c..c262250 100644
--- a/content/renderer/indexed_db/webidbfactory_impl.cc
+++ b/content/renderer/indexed_db/webidbfactory_impl.cc
@@ -36,7 +36,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
       base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
-      nullptr, std::move(task_runner));
+      nullptr);
   factory_->GetDatabaseNames(GetCallbacksProxy(std::move(callbacks_impl)),
                              url::Origin(origin));
 }
@@ -50,7 +50,7 @@
     const WebSecurityOrigin& origin,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
-      base::WrapUnique(callbacks), transaction_id, nullptr, task_runner);
+      base::WrapUnique(callbacks), transaction_id, nullptr);
   auto database_callbacks_impl =
       std::make_unique<IndexedDBDatabaseCallbacksImpl>(
           base::WrapUnique(database_callbacks));
@@ -67,7 +67,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
       base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
-      nullptr, std::move(task_runner));
+      nullptr);
   factory_->DeleteDatabase(GetCallbacksProxy(std::move(callbacks_impl)),
                            url::Origin(origin), name.Utf16(), force_close);
 }
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 79b906c..37b5473 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -722,8 +722,7 @@
   uint32_t options = network::mojom::kURLLoadOptionNone;
   // TODO(jam): use this flag for ResourceDispatcherHost code path once
   // MojoLoading is the only IPC code path.
-  if ((blink::ServiceWorkerUtils::IsServicificationEnabled() ||
-       base::FeatureList::IsEnabled(network::features::kNetworkService)) &&
+  if (blink::ServiceWorkerUtils::IsServicificationEnabled() &&
       request->fetch_request_context_type != REQUEST_CONTEXT_TYPE_FETCH) {
     // MIME sniffing should be disabled for a request initiated by fetch().
     options |= network::mojom::kURLLoadOptionSniffMimeType;
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index 71bdf23..2fc2884 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "content/public/common/request_context_type.h"
 #include "content/renderer/loader/navigation_response_override_parameters.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "content/renderer/loader/test_request_peer.h"
@@ -25,8 +26,13 @@
                                 public network::mojom::URLLoaderFactory {
  protected:
   URLLoaderClientImplTest() : dispatcher_(new ResourceDispatcher()) {
+    auto request = std::make_unique<network::ResourceRequest>();
+    // Set request context type to fetch so that ResourceDispatcher doesn't
+    // install MimeSniffingThrottle, which makes URLLoaderThrottleLoader
+    // defer the request.
+    request->fetch_request_context_type = REQUEST_CONTEXT_TYPE_FETCH;
     request_id_ = dispatcher_->StartAsync(
-        std::make_unique<network::ResourceRequest>(), 0,
+        std::move(request), 0,
         blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false, false,
         std::make_unique<TestRequestPeer>(dispatcher_.get(),
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 9b70963..41936bf 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -39,9 +39,10 @@
     : RenderFrameObserver(render_frame),
       allow_idle_cleanup_(
           content::GetContentClient()->renderer()->IsIdleMediaSuspendEnabled()),
-      background_suspend_enabled_(content::GetContentClient()
-                                      ->renderer()
-                                      ->IsBackgroundMediaSuspendEnabled()),
+      background_suspend_enabled_(
+          content::GetContentClient()
+              ->renderer()
+              ->IsBackgroundMediaSuspendEnabled(render_frame)),
       tick_clock_(base::DefaultTickClock::GetInstance()) {
   idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
   idle_timeout_ = base::TimeDelta::FromSeconds(15);
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index 6e95055e..4588dbd 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -161,15 +161,19 @@
   event->Signal();
 }
 
-void GetSdpAndTypeFromSessionDescription(
+// Initializes |web_description| if |description_callback| returns non-null,
+// otherwise does nothing.
+void GetWebRTCSessionDescriptionFromSessionDescriptionCallback(
     const base::Callback<const webrtc::SessionDescriptionInterface*()>&
         description_callback,
-    std::string* sdp, std::string* type) {
+    blink::WebRTCSessionDescription* web_description) {
   const webrtc::SessionDescriptionInterface* description =
       description_callback.Run();
   if (description) {
-    description->ToString(sdp);
-    *type = description->type();
+    std::string sdp;
+    description->ToString(&sdp);
+    web_description->Initialize(blink::WebString::FromUTF8(description->type()),
+                                blink::WebString::FromUTF8(sdp));
   }
 }
 
@@ -1355,41 +1359,45 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::localDescription");
 
-  // Since local_description returns a pointer to a non-reference-counted object
-  // that lives on the signaling thread, we cannot fetch a pointer to it and use
-  // it directly here. Instead, we access the object completely on the signaling
-  // thread.
-  std::string sdp, type;
+  // Since webrtc::PeerConnectionInterface::local_description() returns a
+  // pointer to a non-reference-counted object that lives on the signaling
+  // thread, we cannot fetch a pointer to it and use it directly here. Instead,
+  // we access the object completely on the signaling thread. Initializing
+  // |local_description| on the signaling thread is safe because we own it and
+  // wait for it to be initialized here.
+  blink::WebRTCSessionDescription local_description;  // IsNull() by default.
   base::Callback<const webrtc::SessionDescriptionInterface*()> description_cb =
       base::Bind(&webrtc::PeerConnectionInterface::local_description,
                  native_peer_connection_);
   RunSynchronousClosureOnSignalingThread(
-      base::Bind(&GetSdpAndTypeFromSessionDescription,
-                 std::move(description_cb), base::Unretained(&sdp),
-                 base::Unretained(&type)),
+      base::Bind(&GetWebRTCSessionDescriptionFromSessionDescriptionCallback,
+                 std::move(description_cb),
+                 base::Unretained(&local_description)),
       "localDescription");
 
-  return CreateWebKitSessionDescription(sdp, type);
+  return local_description;
 }
 
 blink::WebRTCSessionDescription RTCPeerConnectionHandler::RemoteDescription() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::remoteDescription");
-  // Since local_description returns a pointer to a non-reference-counted object
-  // that lives on the signaling thread, we cannot fetch a pointer to it and use
-  // it directly here. Instead, we access the object completely on the signaling
-  // thread.
-  std::string sdp, type;
+  // Since webrtc::PeerConnectionInterface::remote_description() returns a
+  // pointer to a non-reference-counted object that lives on the signaling
+  // thread, we cannot fetch a pointer to it and use it directly here. Instead,
+  // we access the object completely on the signaling thread. Initializing
+  // |remote_description| on the signaling thread is safe because we own it and
+  // wait for it to be initialized here.
+  blink::WebRTCSessionDescription remote_description;  // IsNull() by default.
   base::Callback<const webrtc::SessionDescriptionInterface*()> description_cb =
       base::Bind(&webrtc::PeerConnectionInterface::remote_description,
                  native_peer_connection_);
   RunSynchronousClosureOnSignalingThread(
-      base::Bind(&GetSdpAndTypeFromSessionDescription,
-                 std::move(description_cb), base::Unretained(&sdp),
-                 base::Unretained(&type)),
+      base::Bind(&GetWebRTCSessionDescriptionFromSessionDescriptionCallback,
+                 std::move(description_cb),
+                 base::Unretained(&remote_description)),
       "remoteDescription");
 
-  return CreateWebKitSessionDescription(sdp, type);
+  return remote_description;
 }
 
 webrtc::RTCErrorType RTCPeerConnectionHandler::SetConfiguration(
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
index 51a6af4..06c3314 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
@@ -704,7 +704,7 @@
   pc_handler_->SetLocalDescription(request, description);
   RunMessageLoopsUntilIdle();
   // A description that failed to be applied shouldn't be stored.
-  EXPECT_TRUE(pc_handler_->LocalDescription().Sdp().IsEmpty());
+  EXPECT_TRUE(pc_handler_->LocalDescription().IsNull());
 }
 
 TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
@@ -760,7 +760,7 @@
   pc_handler_->SetRemoteDescription(request, description);
   RunMessageLoopsUntilIdle();
   // A description that failed to be applied shouldn't be stored.
-  EXPECT_TRUE(pc_handler_->RemoteDescription().Sdp().IsEmpty());
+  EXPECT_TRUE(pc_handler_->RemoteDescription().IsNull());
 }
 
 TEST_F(RTCPeerConnectionHandlerTest, setConfiguration) {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index d078133..edc6d8e 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1717,12 +1717,6 @@
 }
 
 void RenderThreadImpl::SetProcessBackgrounded(bool backgrounded) {
-  // Set timer slack to maximum on main thread when in background.
-  base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
-  if (backgrounded)
-    timer_slack = base::TIMER_SLACK_MAXIMUM;
-  main_message_loop_->SetTimerSlack(timer_slack);
-
   main_thread_scheduler_->SetRendererBackgrounded(backgrounded);
   if (backgrounded) {
     needs_to_record_first_active_paint_ = false;
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index c3695033..36901d77 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -639,6 +639,13 @@
   // Subresource loader factory must not be available.
   EXPECT_EQ(nullptr, provider_context->GetSubresourceLoaderFactory());
 
+  // The SetController() call results in another Mojo call to
+  // ControllerServiceWorkerConnector.UpdateController(). Flush that interface
+  // pointer to ensure the message was received.
+  LOG(ERROR) << "3 FlushControllerConnector()";
+  FlushControllerConnector(provider_context.get());
+  LOG(ERROR) << "3 FlushControllerConnector() finished";
+
   // Performing a request using the subresource factory obtained before
   // falls back to the network.
   const GURL kURL3("https://www.example.com/foo3.png");
diff --git a/content/shell/browser/layout_test/layout_test_permission_manager.cc b/content/shell/browser/layout_test/layout_test_permission_manager.cc
index 7cccc6f..a6ad4ea9 100644
--- a/content/shell/browser/layout_test/layout_test_permission_manager.cc
+++ b/content/shell/browser/layout_test/layout_test_permission_manager.cc
@@ -156,11 +156,19 @@
 
 int LayoutTestPermissionManager::SubscribePermissionStatusChange(
     PermissionType permission,
+    RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  // If the request is from a worker, it won't have a RFH.
+  GURL embedding_origin = requesting_origin;
+  if (render_frame_host) {
+    WebContents* web_contents =
+        WebContents::FromRenderFrameHost(render_frame_host);
+    embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
+  }
+
   auto subscription = std::make_unique<Subscription>();
   subscription->permission =
       PermissionDescription(permission, requesting_origin, embedding_origin);
diff --git a/content/shell/browser/layout_test/layout_test_permission_manager.h b/content/shell/browser/layout_test/layout_test_permission_manager.h
index a54e80f..e182e35e 100644
--- a/content/shell/browser/layout_test/layout_test_permission_manager.h
+++ b/content/shell/browser/layout_test/layout_test_permission_manager.h
@@ -51,8 +51,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       PermissionType permission,
+      RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/content/shell/browser/shell_permission_manager.cc b/content/shell/browser/shell_permission_manager.cc
index 25d33b9..3cfcbaa 100644
--- a/content/shell/browser/shell_permission_manager.cc
+++ b/content/shell/browser/shell_permission_manager.cc
@@ -103,8 +103,8 @@
 
 int ShellPermissionManager::SubscribePermissionStatusChange(
     PermissionType permission,
+    RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   return PermissionController::kNoPendingOperation;
 }
diff --git a/content/shell/browser/shell_permission_manager.h b/content/shell/browser/shell_permission_manager.h
index b054b925..844939e 100644
--- a/content/shell/browser/shell_permission_manager.h
+++ b/content/shell/browser/shell_permission_manager.h
@@ -45,8 +45,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       PermissionType permission,
+      RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 70f3441..1e9ee94 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1051,7 +1051,7 @@
       "//ppapi/tests/test_page.css",
       "//ppapi/tests/test_url_loader_data/",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
     ]
   }
diff --git a/content/test/data/frame_tree/page_with_non_flat_transformed_frame.html b/content/test/data/frame_tree/page_with_non_flat_transformed_frame.html
new file mode 100644
index 0000000..817cada6
--- /dev/null
+++ b/content/test/data/frame_tree/page_with_non_flat_transformed_frame.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<style>
+iframe {
+  position:absolute;
+  top: 50px;
+  left: 50px;
+  width: 100px;
+  height: 100px;
+  transform-style: preserve-3d;
+  transform: matrix3d(1,  0,  0,    0,
+                      0,  1,  0,    0,
+                      1,  0,  1,    0,
+                      0,  0, -1000, 1);
+}
+
+</style>
+<html>
+<body>
+<iframe src="/cross-site/baz.com/title1.html"></iframe>
+This page contains a positioned cross-origin iframe with a non-flat transform applied to it.
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 1beb27a..25ee41f3 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -43,10 +43,6 @@
     # Conformance expectations
     # ========================
 
-    # Failing new test added in https://github.com/KhronosGroup/WebGL/pull/2654
-    self.Fail('conformance2/context/incorrect-context-object-behaviour.html',
-        bug=857303)
-
     # Failing new test added in https://github.com/KhronosGroup/WebGL/pull/2665
     self.Fail('conformance2/textures/misc/tex-subimage3d-canvas-bug.html',
               ['linux'], bug=859400)
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index edd9a3a..1fee10f 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -245,6 +245,9 @@
   deps = [
     ":fido",
     "//base",
+    "//device/bluetooth:mocks",
+    "//testing/gmock",
+    "//testing/gtest",
   ]
   libfuzzer_options = [ "max_len=2048" ]
 }
diff --git a/device/fido/ble/fido_ble_connection.cc b/device/fido/ble/fido_ble_connection.cc
index 094f443..c57301e0 100644
--- a/device/fido/ble/fido_ble_connection.cc
+++ b/device/fido/ble/fido_ble_connection.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_gatt_connection.h"
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
@@ -72,32 +71,50 @@
 
 }  // namespace
 
-FidoBleConnection::FidoBleConnection(std::string device_address)
-    : address_(std::move(device_address)), weak_factory_(this) {}
-
 FidoBleConnection::FidoBleConnection(
+    BluetoothAdapter* adapter,
     std::string device_address,
     ConnectionStatusCallback connection_status_callback,
     ReadCallback read_callback)
-    : address_(std::move(device_address)),
+    : adapter_(adapter),
+      address_(std::move(device_address)),
       connection_status_callback_(std::move(connection_status_callback)),
       read_callback_(std::move(read_callback)),
       weak_factory_(this) {
+  DCHECK(adapter_);
+  adapter_->AddObserver(this);
   DCHECK(!address_.empty());
 }
 
 FidoBleConnection::~FidoBleConnection() {
-  if (adapter_)
-    adapter_->RemoveObserver(this);
+  adapter_->RemoveObserver(this);
 }
 
 const BluetoothDevice* FidoBleConnection::GetBleDevice() const {
-  return adapter_ ? adapter_->GetDevice(address()) : nullptr;
+  return adapter_->GetDevice(address());
+}
+
+FidoBleConnection::FidoBleConnection(BluetoothAdapter* adapter,
+                                     std::string device_address)
+    : adapter_(adapter),
+      address_(std::move(device_address)),
+      weak_factory_(this) {
+  adapter_->AddObserver(this);
 }
 
 void FidoBleConnection::Connect() {
-  BluetoothAdapterFactory::GetAdapter(
-      base::Bind(&FidoBleConnection::OnGetAdapter, weak_factory_.GetWeakPtr()));
+  BluetoothDevice* device = adapter_->GetDevice(address_);
+  if (!device) {
+    DLOG(ERROR) << "Failed to get Device.";
+    OnConnectionError();
+    return;
+  }
+
+  device->CreateGattConnection(
+      base::Bind(&FidoBleConnection::OnCreateGattConnection,
+                 weak_factory_.GetWeakPtr()),
+      base::Bind(&FidoBleConnection::OnCreateGattConnectionError,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void FidoBleConnection::ReadControlPointLength(
@@ -269,34 +286,6 @@
       base::Bind(OnWriteError, copyable_callback));
 }
 
-void FidoBleConnection::OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter) {
-  if (!adapter) {
-    DLOG(ERROR) << "Failed to get Adapter.";
-    OnConnectionError();
-    return;
-  }
-
-  DVLOG(2) << "Got Adapter: " << adapter->GetAddress();
-  adapter_ = std::move(adapter);
-  adapter_->AddObserver(this);
-  CreateGattConnection();
-}
-
-void FidoBleConnection::CreateGattConnection() {
-  BluetoothDevice* device = adapter_->GetDevice(address_);
-  if (!device) {
-    DLOG(ERROR) << "Failed to get Device.";
-    OnConnectionError();
-    return;
-  }
-
-  device->CreateGattConnection(
-      base::Bind(&FidoBleConnection::OnCreateGattConnection,
-                 weak_factory_.GetWeakPtr()),
-      base::Bind(&FidoBleConnection::OnCreateGattConnectionError,
-                 weak_factory_.GetWeakPtr()));
-}
-
 void FidoBleConnection::OnCreateGattConnection(
     std::unique_ptr<BluetoothGattConnection> connection) {
   connection_ = std::move(connection);
@@ -410,11 +399,6 @@
 }
 
 const BluetoothRemoteGattService* FidoBleConnection::GetFidoService() const {
-  if (!adapter_) {
-    DLOG(ERROR) << "No adapter present.";
-    return nullptr;
-  }
-
   const BluetoothDevice* device = adapter_->GetDevice(address_);
   if (!device) {
     DLOG(ERROR) << "No device present.";
@@ -440,7 +424,7 @@
                                     BluetoothDevice* device) {
   if (adapter != adapter_ || device->GetAddress() != address_)
     return;
-  CreateGattConnection();
+  Connect();
 }
 
 void FidoBleConnection::DeviceAddressChanged(BluetoothAdapter* adapter,
diff --git a/device/fido/ble/fido_ble_connection.h b/device/fido/ble/fido_ble_connection.h
index 29366b6..24f8298 100644
--- a/device/fido/ble/fido_ble_connection.h
+++ b/device/fido/ble/fido_ble_connection.h
@@ -62,7 +62,8 @@
   using ServiceRevisionsCallback =
       base::OnceCallback<void(std::set<ServiceRevision>)>;
 
-  FidoBleConnection(std::string device_address,
+  FidoBleConnection(BluetoothAdapter* adapter,
+                    std::string device_address,
                     ConnectionStatusCallback connection_status_callback,
                     ReadCallback read_callback);
   ~FidoBleConnection() override;
@@ -79,8 +80,10 @@
                                     WriteCallback callback);
 
  protected:
-  explicit FidoBleConnection(std::string device_address);
+  // Used for testing.
+  FidoBleConnection(BluetoothAdapter* adapter, std::string device_address);
 
+  scoped_refptr<BluetoothAdapter> adapter_;
   std::string address_;
   ConnectionStatusCallback connection_status_callback_;
   ReadCallback read_callback_;
@@ -100,9 +103,6 @@
   void GattServicesDiscovered(BluetoothAdapter* adapter,
                               BluetoothDevice* device) override;
 
-  void OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter);
-
-  void CreateGattConnection();
   void OnCreateGattConnection(
       std::unique_ptr<BluetoothGattConnection> connection);
   void OnCreateGattConnectionError(
@@ -142,7 +142,6 @@
   static void OnWriteError(WriteCallback callback,
                            BluetoothGattService::GattErrorCode error_code);
 
-  scoped_refptr<BluetoothAdapter> adapter_;
   std::unique_ptr<BluetoothGattConnection> connection_;
   std::unique_ptr<BluetoothGattNotifySession> notify_session_;
 
diff --git a/device/fido/ble/fido_ble_connection_unittest.cc b/device/fido/ble/fido_ble_connection_unittest.cc
index c214c81..6f81ba39 100644
--- a/device/fido/ble/fido_ble_connection_unittest.cc
+++ b/device/fido/ble/fido_ble_connection_unittest.cc
@@ -135,6 +135,8 @@
     BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
   }
 
+  BluetoothAdapter* adapter() { return adapter_.get(); }
+
   void AddU2Device(const std::string& device_address) {
     auto u2f_device = std::make_unique<NiceMockBluetoothDevice>(
         adapter_.get(), /* bluetooth_class */ 0u,
@@ -359,7 +361,7 @@
   auto connect_do_nothing = [](bool) {};
   auto read_do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                base::BindRepeating(connect_do_nothing),
                                base::BindRepeating(read_do_nothing));
   connection.Connect();
@@ -375,7 +377,7 @@
   TestConnectionStatusCallback connection_status_callback;
   auto do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(do_nothing));
   connection.Connect();
@@ -390,7 +392,7 @@
   SetupConnectingU2fDevice(device_address);
 
   auto do_nothing = [](std::vector<uint8_t>) {};
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(do_nothing));
   connection.Connect();
@@ -401,7 +403,7 @@
   const std::string device_address = BluetoothTest::kTestDeviceAddress1;
   TestConnectionStatusCallback connection_status_callback;
   auto do_nothing = [](std::vector<uint8_t>) {};
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(do_nothing));
   connection.Connect();
@@ -421,7 +423,7 @@
   AddU2Device(device_address);
   SetupConnectingU2fDevice(device_address);
   auto do_nothing = [](std::vector<uint8_t>) {};
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(do_nothing));
   connection.Connect();
@@ -440,7 +442,7 @@
 
   AddU2Device(device_address);
   SetupConnectingU2fDevice(device_address);
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                read_callback.GetCallback());
   connection.Connect();
@@ -462,7 +464,7 @@
   SetupConnectingU2fDevice(device_address);
   auto read_do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(read_do_nothing));
   connection.Connect();
@@ -499,7 +501,7 @@
   SetupConnectingU2fDevice(device_address);
   auto read_do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(read_do_nothing));
   connection.Connect();
@@ -599,7 +601,7 @@
   SetupConnectingU2fDevice(device_address);
   auto read_do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(read_do_nothing));
   connection.Connect();
@@ -625,7 +627,7 @@
   SetupConnectingU2fDevice(device_address);
   auto read_do_nothing = [](std::vector<uint8_t>) {};
 
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(read_do_nothing));
   connection.Connect();
@@ -672,7 +674,7 @@
   AddU2Device(device_address);
   SetupConnectingU2fDevice(device_address);
   auto do_nothing = [](std::vector<uint8_t>) {};
-  FidoBleConnection connection(device_address,
+  FidoBleConnection connection(adapter(), device_address,
                                connection_status_callback.GetCallback(),
                                base::BindRepeating(do_nothing));
   connection.Connect();
diff --git a/device/fido/ble/fido_ble_device.cc b/device/fido/ble/fido_ble_device.cc
index 1d47ab0..b45c554 100644
--- a/device/fido/ble/fido_ble_device.cc
+++ b/device/fido/ble/fido_ble_device.cc
@@ -16,9 +16,10 @@
 
 namespace device {
 
-FidoBleDevice::FidoBleDevice(std::string address) : weak_factory_(this) {
+FidoBleDevice::FidoBleDevice(BluetoothAdapter* adapter, std::string address)
+    : weak_factory_(this) {
   connection_ = std::make_unique<FidoBleConnection>(
-      std::move(address),
+      adapter, std::move(address),
       base::BindRepeating(&FidoBleDevice::OnConnectionStatus,
                           base::Unretained(this)),
       base::BindRepeating(&FidoBleDevice::OnStatusMessage,
diff --git a/device/fido/ble/fido_ble_device.h b/device/fido/ble/fido_ble_device.h
index 34e7b55..54e340c4 100644
--- a/device/fido/ble/fido_ble_device.h
+++ b/device/fido/ble/fido_ble_device.h
@@ -24,12 +24,13 @@
 
 namespace device {
 
+class BluetoothAdapter;
 class FidoBleFrame;
 
 class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDevice : public FidoDevice {
  public:
   using FrameCallback = FidoBleTransaction::FrameCallback;
-  explicit FidoBleDevice(std::string address);
+  FidoBleDevice(BluetoothAdapter* adapter, std::string address);
   explicit FidoBleDevice(std::unique_ptr<FidoBleConnection> connection);
   ~FidoBleDevice() override;
 
diff --git a/device/fido/ble/fido_ble_device_unittest.cc b/device/fido/ble/fido_ble_device_unittest.cc
index b40cba2..16eba7fd 100644
--- a/device/fido/ble/fido_ble_device_unittest.cc
+++ b/device/fido/ble/fido_ble_device_unittest.cc
@@ -75,7 +75,7 @@
  public:
   FidoBleDeviceTest() {
     auto connection = std::make_unique<MockFidoBleConnection>(
-        BluetoothTestBase::kTestDeviceAddress1);
+        adapter_.get(), BluetoothTestBase::kTestDeviceAddress1);
     connection_ = connection.get();
     device_ = std::make_unique<FidoBleDevice>(std::move(connection));
     connection_->connection_status_callback() =
@@ -83,6 +83,7 @@
     connection_->read_callback() = device_->GetReadCallbackForTesting();
   }
 
+  MockBluetoothAdapter* adapter() { return adapter_.get(); }
   FidoBleDevice* device() { return device_.get(); }
   MockFidoBleConnection* connection() { return connection_; }
 
@@ -102,6 +103,8 @@
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
 
  private:
+  scoped_refptr<MockBluetoothAdapter> adapter_ =
+      base::MakeRefCounted<NiceMockBluetoothAdapter>();
   MockFidoBleConnection* connection_;
   std::unique_ptr<FidoBleDevice> device_;
 };
@@ -223,10 +226,7 @@
   // By default, a device is not in pairing mode.
   EXPECT_FALSE(device()->IsInPairingMode());
 
-  // Initiate default connection behavior, which will attempt to obtain an
-  // adapter.
-  auto mock_adapter = base::MakeRefCounted<NiceMockBluetoothAdapter>();
-  BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+  // Initiate default connection behavior.
   EXPECT_CALL(*connection(), Connect()).WillOnce(Invoke([this] {
     connection()->FidoBleConnection::Connect();
   }));
@@ -235,11 +235,11 @@
   // Add a mock fido device. This should also not be considered to be in pairing
   // mode.
   auto mock_bluetooth_device = std::make_unique<NiceMockBluetoothDevice>(
-      mock_adapter.get(), /* bluetooth_class */ 0u,
+      adapter(), /* bluetooth_class */ 0u,
       BluetoothTestBase::kTestDeviceNameU2f,
       BluetoothTestBase::kTestDeviceAddress1, /* paired */ true,
       /* connected */ false);
-  EXPECT_CALL(*mock_adapter, GetDevice(BluetoothTestBase::kTestDeviceAddress1))
+  EXPECT_CALL(*adapter(), GetDevice(BluetoothTestBase::kTestDeviceAddress1))
       .WillRepeatedly(Return(mock_bluetooth_device.get()));
 
   EXPECT_FALSE(device()->IsInPairingMode());
diff --git a/device/fido/ble/fido_ble_discovery.cc b/device/fido/ble/fido_ble_discovery.cc
index 41b4c542..9b309c5 100644
--- a/device/fido/ble/fido_ble_discovery.cc
+++ b/device/fido/ble/fido_ble_discovery.cc
@@ -34,7 +34,8 @@
   for (BluetoothDevice* device : adapter()->GetDevices()) {
     if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
       VLOG(2) << "U2F BLE device: " << device->GetAddress();
-      AddDevice(std::make_unique<FidoBleDevice>(device->GetAddress()));
+      AddDevice(
+          std::make_unique<FidoBleDevice>(adapter(), device->GetAddress()));
     }
   }
 
@@ -56,7 +57,7 @@
                                    BluetoothDevice* device) {
   if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
     VLOG(2) << "Discovered U2F BLE device: " << device->GetAddress();
-    AddDevice(std::make_unique<FidoBleDevice>(device->GetAddress()));
+    AddDevice(std::make_unique<FidoBleDevice>(adapter, device->GetAddress()));
   }
 }
 
@@ -66,7 +67,7 @@
       !GetDevice(FidoBleDevice::GetId(device->GetAddress()))) {
     VLOG(2) << "Discovered U2F service on existing BLE device: "
             << device->GetAddress();
-    AddDevice(std::make_unique<FidoBleDevice>(device->GetAddress()));
+    AddDevice(std::make_unique<FidoBleDevice>(adapter, device->GetAddress()));
   }
 }
 
diff --git a/device/fido/ble/mock_fido_ble_connection.cc b/device/fido/ble/mock_fido_ble_connection.cc
index bb42a169..c2d7fe5 100644
--- a/device/fido/ble/mock_fido_ble_connection.cc
+++ b/device/fido/ble/mock_fido_ble_connection.cc
@@ -8,8 +8,9 @@
 
 namespace device {
 
-MockFidoBleConnection::MockFidoBleConnection(std::string device_address)
-    : FidoBleConnection(std::move(device_address)) {}
+MockFidoBleConnection::MockFidoBleConnection(BluetoothAdapter* adapter,
+                                             std::string device_address)
+    : FidoBleConnection(adapter, std::move(device_address)) {}
 
 MockFidoBleConnection::~MockFidoBleConnection() = default;
 
diff --git a/device/fido/ble/mock_fido_ble_connection.h b/device/fido/ble/mock_fido_ble_connection.h
index 6fa4ea8d..7753ae90 100644
--- a/device/fido/ble/mock_fido_ble_connection.h
+++ b/device/fido/ble/mock_fido_ble_connection.h
@@ -15,9 +15,11 @@
 
 namespace device {
 
+class BluetoothAdapter;
+
 class MockFidoBleConnection : public FidoBleConnection {
  public:
-  explicit MockFidoBleConnection(std::string device_address);
+  MockFidoBleConnection(BluetoothAdapter* adapter, std::string device_address);
   ~MockFidoBleConnection() override;
 
   MOCK_METHOD0(Connect, void());
@@ -50,4 +52,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_FIDO_MOCK_FIDO_BLE_CONNECTION_H_
+#endif  // DEVICE_FIDO_BLE_MOCK_FIDO_BLE_CONNECTION_H_
diff --git a/device/fido/cable/fido_cable_device.cc b/device/fido/cable/fido_cable_device.cc
index 52082ee..1c5dd60 100644
--- a/device/fido/cable/fido_cable_device.cc
+++ b/device/fido/cable/fido_cable_device.cc
@@ -113,8 +113,8 @@
 
 // FidoCableDevice::EncryptionData ----------------------------------------
 
-FidoCableDevice::FidoCableDevice(std::string address)
-    : FidoBleDevice(std::move(address)), weak_factory_(this) {}
+FidoCableDevice::FidoCableDevice(BluetoothAdapter* adapter, std::string address)
+    : FidoBleDevice(adapter, std::move(address)), weak_factory_(this) {}
 
 FidoCableDevice::FidoCableDevice(std::unique_ptr<FidoBleConnection> connection)
     : FidoBleDevice(std::move(connection)), weak_factory_(this) {}
diff --git a/device/fido/cable/fido_cable_device.h b/device/fido/cable/fido_cable_device.h
index c2e8966..29e3907f 100644
--- a/device/fido/cable/fido_cable_device.h
+++ b/device/fido/cable/fido_cable_device.h
@@ -20,8 +20,9 @@
 
 namespace device {
 
-class FidoBleFrame;
+class BluetoothAdapter;
 class FidoBleConnection;
+class FidoBleFrame;
 
 class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDevice : public FidoBleDevice {
  public:
@@ -44,7 +45,7 @@
 
   using FrameCallback = FidoBleTransaction::FrameCallback;
 
-  FidoCableDevice(std::string address);
+  FidoCableDevice(BluetoothAdapter* adapter, std::string address);
   // Constructor used for testing purposes.
   FidoCableDevice(std::unique_ptr<FidoBleConnection> connection);
   ~FidoCableDevice() override;
diff --git a/device/fido/cable/fido_cable_device_unittest.cc b/device/fido/cable/fido_cable_device_unittest.cc
index 8cd0f968..29cb49abf 100644
--- a/device/fido/cable/fido_cable_device_unittest.cc
+++ b/device/fido/cable/fido_cable_device_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "crypto/aead.h"
 #include "device/bluetooth/test/bluetooth_test.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/fido/ble/mock_fido_ble_connection.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/test_callback_receiver.h"
@@ -31,6 +32,7 @@
 using ::testing::Test;
 using TestDeviceCallbackReceiver =
     test::ValueCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
+using NiceMockBluetoothAdapter = ::testing::NiceMock<MockBluetoothAdapter>;
 
 // Sufficiently large test control point length as we are not interested
 // in testing fragmentations of BLE messages. All Cable messages are encrypted
@@ -128,7 +130,7 @@
  public:
   FidoCableDeviceTest() {
     auto connection = std::make_unique<MockFidoBleConnection>(
-        BluetoothTestBase::kTestDeviceAddress1);
+        adapter_.get(), BluetoothTestBase::kTestDeviceAddress1);
     connection_ = connection.get();
     device_ = std::make_unique<FidoCableDevice>(std::move(connection));
     device_->SetEncryptionData(kTestSessionKey, kTestEncryptionNonce);
@@ -157,6 +159,8 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
  private:
+  scoped_refptr<MockBluetoothAdapter> adapter_ =
+      base::MakeRefCounted<NiceMockBluetoothAdapter>();
   FakeCableAuthenticator authenticator_;
   MockFidoBleConnection* connection_;
   std::unique_ptr<FidoCableDevice> device_;
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index 158cd92..0294fad8 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -265,7 +265,8 @@
   if (!extract_success)
     return;
 
-  auto cable_device = std::make_unique<FidoCableDevice>(device->GetAddress());
+  auto cable_device =
+      std::make_unique<FidoCableDevice>(adapter, device->GetAddress());
   // At most one handshake messages should be exchanged for each Cable device.
   if (!base::ContainsKey(cable_handshake_handlers_, cable_device->GetId())) {
     ConductEncryptionHandshake(std::move(cable_device),
diff --git a/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
index 35a4351..5b0432e0 100644
--- a/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
+++ b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
@@ -8,9 +8,13 @@
 #include <array>
 
 #include "base/containers/span.h"
+#include "base/memory/ref_counted.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/fido/cable/fido_cable_device.h"
 #include "device/fido/cable/fido_cable_handshake_handler.h"
 #include "device/fido/fido_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
@@ -30,7 +34,9 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) {
   auto data_span = base::make_span(raw_data, size);
-  device::FidoCableDevice test_cable_device(kTestDeviceAddress);
+  auto adapter =
+      base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
+  device::FidoCableDevice test_cable_device(adapter.get(), kTestDeviceAddress);
   device::FidoCableHandshakeHandler handshake_handler(
       &test_cable_device, kTestNonce, kTestSessionPreKey);
   handshake_handler.ValidateAuthenticatorHandshakeMessage(data_span);
diff --git a/device/fido/cable/fido_cable_handshake_handler_unittest.cc b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
index b2e2c08b..4fea793 100644
--- a/device/fido/cable/fido_cable_handshake_handler_unittest.cc
+++ b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
@@ -19,6 +19,7 @@
 #include "crypto/hkdf.h"
 #include "crypto/hmac.h"
 #include "device/bluetooth/test/bluetooth_test.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/fido/ble/fido_ble_frames.h"
 #include "device/fido/ble/mock_fido_ble_connection.h"
 #include "device/fido/cable/fido_cable_device.h"
@@ -37,6 +38,7 @@
 using ::testing::Test;
 using TestDeviceCallbackReceiver =
     test::ValueCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
+using NiceMockBluetoothAdapter = ::testing::NiceMock<MockBluetoothAdapter>;
 
 // Sufficiently large test control point length as we are not interested
 // in testing fragmentations of BLE messages. All Cable messages are encrypted
@@ -254,7 +256,7 @@
  public:
   FidoCableHandshakeHandlerTest() {
     auto connection = std::make_unique<MockFidoBleConnection>(
-        BluetoothTestBase::kTestDeviceAddress1);
+        adapter_.get(), BluetoothTestBase::kTestDeviceAddress1);
     connection_ = connection.get();
     device_ = std::make_unique<FidoCableDevice>(std::move(connection));
 
@@ -290,6 +292,8 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
  private:
+  scoped_refptr<MockBluetoothAdapter> adapter_ =
+      base::MakeRefCounted<NiceMockBluetoothAdapter>();
   FakeCableAuthenticator authenticator_;
   MockFidoBleConnection* connection_;
   std::unique_ptr<FidoCableDevice> device_;
diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn
index 77132bf..0ab6e1a 100644
--- a/device/serial/BUILD.gn
+++ b/device/serial/BUILD.gn
@@ -20,7 +20,6 @@
       ":test_support",
       "//device:device_unittests",
       "//services/device/serial",
-      "//tools/battor_agent:battor_agent_lib",
     ]
 
     output_name = "device_serial"
@@ -78,19 +77,4 @@
       ]
     }
   }
-
-  static_library("test_support") {
-    # TODO(leonhsl): Merge necessary parts of TestSerialIoHandler into
-    # battor_connection_impl_unittest.cc to hide serial impl completely.
-    visibility = [ "//tools/battor_agent:battor_agent_unittests" ]
-
-    sources = [
-      "test_serial_io_handler.cc",
-      "test_serial_io_handler.h",
-    ]
-
-    public_deps = [
-      ":serial",
-    ]
-  }
 }
diff --git a/device/serial/test_serial_io_handler.cc b/device/serial/test_serial_io_handler.cc
deleted file mode 100644
index c04c2a9..0000000
--- a/device/serial/test_serial_io_handler.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2014 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 "device/serial/test_serial_io_handler.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "services/device/public/mojom/serial.mojom.h"
-
-namespace device {
-
-TestSerialIoHandler::TestSerialIoHandler()
-    : SerialIoHandler(NULL),
-      opened_(false),
-      dtr_(false),
-      rts_(false),
-      flushes_(0) {}
-
-scoped_refptr<SerialIoHandler> TestSerialIoHandler::Create() {
-  return scoped_refptr<SerialIoHandler>(new TestSerialIoHandler);
-}
-
-void TestSerialIoHandler::Open(const std::string& port,
-                               const mojom::SerialConnectionOptions& options,
-                               OpenCompleteCallback callback) {
-  DCHECK(!opened_);
-  opened_ = true;
-  ConfigurePort(options);
-  std::move(callback).Run(true);
-}
-
-void TestSerialIoHandler::ReadImpl() {
-  if (!pending_read_buffer())
-    return;
-  if (buffer_.empty())
-    return;
-
-  size_t num_bytes =
-      std::min(buffer_.size(), static_cast<size_t>(pending_read_buffer_len()));
-  memcpy(pending_read_buffer(), buffer_.data(), num_bytes);
-  buffer_.erase(buffer_.begin(), buffer_.begin() + num_bytes);
-  ReadCompleted(static_cast<uint32_t>(num_bytes),
-                mojom::SerialReceiveError::NONE);
-}
-
-void TestSerialIoHandler::CancelReadImpl() {
-  ReadCompleted(0, read_cancel_reason());
-}
-
-void TestSerialIoHandler::WriteImpl() {
-  if (send_callback_) {
-    std::move(send_callback_).Run();
-    return;
-  }
-  buffer_.insert(buffer_.end(), pending_write_buffer(),
-                 pending_write_buffer() + pending_write_buffer_len());
-  WriteCompleted(pending_write_buffer_len(), mojom::SerialSendError::NONE);
-  if (pending_read_buffer())
-    ReadImpl();
-}
-
-void TestSerialIoHandler::CancelWriteImpl() {
-  WriteCompleted(0, write_cancel_reason());
-}
-
-bool TestSerialIoHandler::ConfigurePortImpl() {
-  info_.bitrate = options().bitrate;
-  info_.data_bits = options().data_bits;
-  info_.parity_bit = options().parity_bit;
-  info_.stop_bits = options().stop_bits;
-  info_.cts_flow_control = options().cts_flow_control;
-  return true;
-}
-
-mojom::SerialDeviceControlSignalsPtr TestSerialIoHandler::GetControlSignals()
-    const {
-  auto signals = mojom::SerialDeviceControlSignals::New();
-  *signals = device_control_signals_;
-  return signals;
-}
-
-mojom::SerialConnectionInfoPtr TestSerialIoHandler::GetPortInfo() const {
-  auto info = mojom::SerialConnectionInfo::New();
-  *info = info_;
-  return info;
-}
-
-bool TestSerialIoHandler::Flush() const {
-  flushes_++;
-  return true;
-}
-
-bool TestSerialIoHandler::SetControlSignals(
-    const mojom::SerialHostControlSignals& signals) {
-  if (signals.has_dtr)
-    dtr_ = signals.dtr;
-  if (signals.has_rts)
-    rts_ = signals.rts;
-  return true;
-}
-
-bool TestSerialIoHandler::SetBreak() {
-  return true;
-}
-
-bool TestSerialIoHandler::ClearBreak() {
-  return true;
-}
-
-void TestSerialIoHandler::ForceReceiveError(
-    device::mojom::SerialReceiveError error) {
-  ReadCompleted(0, error);
-}
-
-void TestSerialIoHandler::ForceSendError(device::mojom::SerialSendError error) {
-  WriteCompleted(0, error);
-}
-
-TestSerialIoHandler::~TestSerialIoHandler() = default;
-
-}  // namespace device
diff --git a/device/serial/test_serial_io_handler.h b/device/serial/test_serial_io_handler.h
deleted file mode 100644
index d60be3a..0000000
--- a/device/serial/test_serial_io_handler.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2014 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 DEVICE_SERIAL_TEST_SERIAL_IO_HANDLER_H_
-#define DEVICE_SERIAL_TEST_SERIAL_IO_HANDLER_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "device/serial/serial_io_handler.h"
-#include "services/device/public/mojom/serial.mojom.h"
-
-namespace device {
-
-class TestSerialIoHandler : public SerialIoHandler {
- public:
-  TestSerialIoHandler();
-
-  static scoped_refptr<SerialIoHandler> Create();
-
-  // SerialIoHandler overrides.
-  void Open(const std::string& port,
-            const mojom::SerialConnectionOptions& options,
-            OpenCompleteCallback callback) override;
-  void ReadImpl() override;
-  void CancelReadImpl() override;
-  void WriteImpl() override;
-  void CancelWriteImpl() override;
-  bool ConfigurePortImpl() override;
-  mojom::SerialDeviceControlSignalsPtr GetControlSignals() const override;
-  mojom::SerialConnectionInfoPtr GetPortInfo() const override;
-  bool Flush() const override;
-  bool SetControlSignals(
-      const mojom::SerialHostControlSignals& signals) override;
-  bool SetBreak() override;
-  bool ClearBreak() override;
-  void ForceReceiveError(device::mojom::SerialReceiveError error);
-  void ForceSendError(device::mojom::SerialSendError error);
-
-  mojom::SerialConnectionInfo* connection_info() { return &info_; }
-  mojom::SerialDeviceControlSignals* device_control_signals() {
-    return &device_control_signals_;
-  }
-  bool dtr() { return dtr_; }
-  bool rts() { return rts_; }
-  int flushes() { return flushes_; }
-  // This callback will be called when this IoHandler processes its next write,
-  // instead of the normal behavior of echoing the data to reads.
-  void set_send_callback(base::OnceClosure callback) {
-    send_callback_ = std::move(callback);
-  }
-
- protected:
-  ~TestSerialIoHandler() override;
-
- private:
-  bool opened_;
-  mojom::SerialConnectionInfo info_;
-  mojom::SerialDeviceControlSignals device_control_signals_;
-  bool dtr_;
-  bool rts_;
-  mutable int flushes_;
-  std::vector<uint8_t> buffer_;
-  base::OnceClosure send_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestSerialIoHandler);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_SERIAL_TEST_SERIAL_IO_HANDLER_H_
diff --git a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
index 03e7d72..b151a27 100644
--- a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
+++ b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
@@ -26,7 +26,7 @@
 
 CardboardGamepadDataFetcher::Factory::Factory(
     CardboardGamepadDataProvider* data_provider,
-    unsigned int display_id)
+    device::mojom::XRDeviceId display_id)
     : data_provider_(data_provider), display_id_(display_id) {
   DVLOG(1) << __FUNCTION__ << "=" << this;
 }
@@ -47,7 +47,7 @@
 
 CardboardGamepadDataFetcher::CardboardGamepadDataFetcher(
     CardboardGamepadDataProvider* data_provider,
-    unsigned int display_id)
+    device::mojom::XRDeviceId display_id)
     : display_id_(display_id) {
   // Called on UI thread.
   DVLOG(1) << __FUNCTION__ << "=" << this;
@@ -93,7 +93,7 @@
     pad.buttons_length = 1;
     pad.axes_length = 0;
 
-    pad.display_id = display_id_;
+    pad.display_id = static_cast<unsigned int>(display_id_);
 
     pad.hand = GamepadHand::kNone;
   }
diff --git a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.h b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.h
index 0b6193f..0fe4651 100644
--- a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.h
+++ b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.h
@@ -9,6 +9,7 @@
 
 #include "device/gamepad/gamepad_data_fetcher.h"
 #include "device/vr/android/gvr/cardboard_gamepad_data_provider.h"
+#include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_export.h"
 
 namespace device {
@@ -17,18 +18,19 @@
  public:
   class Factory : public GamepadDataFetcherFactory {
    public:
-    Factory(CardboardGamepadDataProvider*, unsigned int display_id);
+    Factory(CardboardGamepadDataProvider*,
+            device::mojom::XRDeviceId display_id);
     ~Factory() override;
     std::unique_ptr<GamepadDataFetcher> CreateDataFetcher() override;
     GamepadSource source() override;
 
    private:
     CardboardGamepadDataProvider* data_provider_;
-    unsigned int display_id_;
+    device::mojom::XRDeviceId display_id_;
   };
 
   CardboardGamepadDataFetcher(CardboardGamepadDataProvider*,
-                              unsigned int display_id);
+                              device::mojom::XRDeviceId display_id);
   ~CardboardGamepadDataFetcher() override;
 
   GamepadSource source() override;
@@ -41,7 +43,7 @@
   void SetGamepadData(CardboardGamepadData);
 
  private:
-  unsigned int display_id_;
+  device::mojom::XRDeviceId display_id_;
   CardboardGamepadData gamepad_data_;
 
   DISALLOW_COPY_AND_ASSIGN(CardboardGamepadDataFetcher);
diff --git a/device/vr/android/gvr/gvr_delegate_provider.h b/device/vr/android/gvr/gvr_delegate_provider.h
index f45939ae..60c3419 100644
--- a/device/vr/android/gvr/gvr_delegate_provider.h
+++ b/device/vr/android/gvr/gvr_delegate_provider.h
@@ -19,7 +19,7 @@
  public:
   GvrDelegateProvider() = default;
   virtual bool ShouldDisableGvrDevice() = 0;
-  virtual void SetDeviceId(unsigned int device_id) = 0;
+  virtual void SetDeviceId(mojom::XRDeviceId device_id) = 0;
   virtual void StartWebXRPresentation(
       mojom::VRDisplayInfoPtr display_info,
       mojom::XRRuntimeSessionOptionsPtr options,
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 73913dd..c47946f2 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -93,12 +93,12 @@
 }
 
 mojom::VRDisplayInfoPtr CreateVRDisplayInfo(gvr::GvrApi* gvr_api,
-                                            uint32_t device_id) {
+                                            mojom::XRDeviceId device_id) {
   TRACE_EVENT0("input", "GvrDelegate::CreateVRDisplayInfo");
 
   mojom::VRDisplayInfoPtr device = mojom::VRDisplayInfo::New();
 
-  device->index = device_id;
+  device->id = device_id;
 
   device->capabilities = mojom::VRDisplayCapabilities::New();
   device->capabilities->hasPosition = false;
@@ -143,7 +143,7 @@
 }
 
 GvrDevice::GvrDevice()
-    : VRDeviceBase(VRDeviceId::GVR_DEVICE_ID),
+    : VRDeviceBase(mojom::XRDeviceId::GVR_DEVICE_ID),
       exclusive_controller_binding_(this),
       weak_ptr_factory_(this) {
   GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index ea77025b..56f8e79 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -12,10 +12,10 @@
 GvrDeviceProvider::~GvrDeviceProvider() = default;
 
 void GvrDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
     base::OnceClosure initialization_complete) {
   vr_device_ = GvrDevice::Create();
   if (vr_device_)
diff --git a/device/vr/android/gvr/gvr_device_provider.h b/device/vr/android/gvr/gvr_device_provider.h
index c833e473..527b8471 100644
--- a/device/vr/android/gvr/gvr_device_provider.h
+++ b/device/vr/android/gvr/gvr_device_provider.h
@@ -21,10 +21,10 @@
   ~GvrDeviceProvider() override;
 
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
       base::OnceClosure initialization_complete) override;
 
   bool Initialized() override;
diff --git a/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc b/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
index f48fcd3..0d50dd8c 100644
--- a/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
+++ b/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
@@ -26,7 +26,7 @@
 }  // namespace
 
 GvrGamepadDataFetcher::Factory::Factory(GvrGamepadDataProvider* data_provider,
-                                        unsigned int display_id)
+                                        mojom::XRDeviceId display_id)
     : data_provider_(data_provider), display_id_(display_id) {
   DVLOG(1) << __FUNCTION__ << "=" << this;
 }
@@ -46,7 +46,7 @@
 
 GvrGamepadDataFetcher::GvrGamepadDataFetcher(
     GvrGamepadDataProvider* data_provider,
-    unsigned int display_id)
+    mojom::XRDeviceId display_id)
     : display_id_(display_id) {
   // Called on UI thread.
   DVLOG(1) << __FUNCTION__ << "=" << this;
@@ -93,7 +93,7 @@
     pad.buttons_length = 1;
     pad.axes_length = 2;
 
-    pad.display_id = display_id_;
+    pad.display_id = static_cast<unsigned int>(display_id_);
 
     pad.is_xr = true;
 
diff --git a/device/vr/android/gvr/gvr_gamepad_data_fetcher.h b/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
index 816046e5..e4a0da5 100644
--- a/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
+++ b/device/vr/android/gvr/gvr_gamepad_data_fetcher.h
@@ -9,6 +9,7 @@
 
 #include "device/gamepad/gamepad_data_fetcher.h"
 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
+#include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_export.h"
 
 namespace device {
@@ -17,17 +18,17 @@
  public:
   class Factory : public GamepadDataFetcherFactory {
    public:
-    Factory(GvrGamepadDataProvider*, unsigned int display_id);
+    Factory(GvrGamepadDataProvider*, mojom::XRDeviceId display_id);
     ~Factory() override;
     std::unique_ptr<GamepadDataFetcher> CreateDataFetcher() override;
     GamepadSource source() override;
 
    private:
     GvrGamepadDataProvider* data_provider_;
-    unsigned int display_id_;
+    mojom::XRDeviceId display_id_;
   };
 
-  GvrGamepadDataFetcher(GvrGamepadDataProvider*, unsigned int display_id);
+  GvrGamepadDataFetcher(GvrGamepadDataProvider*, mojom::XRDeviceId display_id);
   ~GvrGamepadDataFetcher() override;
 
   GamepadSource source() override;
@@ -40,7 +41,7 @@
   void SetGamepadData(GvrGamepadData);
 
  private:
-  unsigned int display_id_;
+  mojom::XRDeviceId display_id_;
   GvrGamepadData gamepad_data_;
 
   DISALLOW_COPY_AND_ASSIGN(GvrGamepadDataFetcher);
diff --git a/device/vr/buildflags/BUILD.gn b/device/vr/buildflags/BUILD.gn
index fa4c3d9..2bbefac 100644
--- a/device/vr/buildflags/BUILD.gn
+++ b/device/vr/buildflags/BUILD.gn
@@ -10,8 +10,9 @@
   header = "buildflags.h"
   flags = [
     "ENABLE_ARCORE=$enable_arcore",
-    "ENABLE_VR=$enable_vr",
-    "ENABLE_OPENVR=$enable_openvr",
+    "ENABLE_ISOLATED_XR_SERVICE=$enable_isolated_xr_service",
     "ENABLE_OCULUS_VR=$enable_oculus_vr",
+    "ENABLE_OPENVR=$enable_openvr",
+    "ENABLE_VR=$enable_vr",
   ]
 }
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni
index eb1a3885..13f05de 100644
--- a/device/vr/buildflags/buildflags.gni
+++ b/device/vr/buildflags/buildflags.gni
@@ -50,4 +50,11 @@
   # directories, we can stop requiring |enable_vr| here.
   enable_arcore = enable_vr && is_android && !is_chromecast &&
                   (current_cpu == "arm" || current_cpu == "arm64")
+
+  # When enabled, host Desktop VR devices (OpenVR and Oculus) in a separate
+  # process.  When disabled, and Oculus/OpenVR are enabled, they are hosted
+  # in the browser process.
+  # TODO(billorr): Enable by default when OpenVR or Oculus are enabled after
+  # tests and controllers are working with the isolated process.
+  enable_isolated_xr_service = false
 }
diff --git a/device/vr/isolated_gamepad_data_fetcher.cc b/device/vr/isolated_gamepad_data_fetcher.cc
index 22d15dd..b78f5d5a 100644
--- a/device/vr/isolated_gamepad_data_fetcher.cc
+++ b/device/vr/isolated_gamepad_data_fetcher.cc
@@ -8,7 +8,7 @@
 namespace device {
 
 IsolatedGamepadDataFetcher::Factory::Factory(
-    VRDeviceId display_id,
+    device::mojom::XRDeviceId display_id,
     device::mojom::IsolatedXRGamepadProviderFactoryPtr factory)
     : display_id_(display_id), factory_(std::move(factory)) {}
 
@@ -23,12 +23,13 @@
 }
 
 GamepadSource IsolatedGamepadDataFetcher::Factory::source() {
-  return (display_id_ == VRDeviceId::OPENVR_DEVICE_ID) ? GAMEPAD_SOURCE_OPENVR
-                                                       : GAMEPAD_SOURCE_OCULUS;
+  return (display_id_ == device::mojom::XRDeviceId::OPENVR_DEVICE_ID)
+             ? GAMEPAD_SOURCE_OPENVR
+             : GAMEPAD_SOURCE_OCULUS;
 }
 
 IsolatedGamepadDataFetcher::IsolatedGamepadDataFetcher(
-    VRDeviceId display_id,
+    device::mojom::XRDeviceId display_id,
     device::mojom::IsolatedXRGamepadProviderPtr provider)
     : display_id_(display_id) {
   // We bind provider_ on the poling thread, but we're created on the main UI
@@ -39,8 +40,9 @@
 IsolatedGamepadDataFetcher::~IsolatedGamepadDataFetcher() = default;
 
 GamepadSource IsolatedGamepadDataFetcher::source() {
-  return (display_id_ == VRDeviceId::OPENVR_DEVICE_ID) ? GAMEPAD_SOURCE_OPENVR
-                                                       : GAMEPAD_SOURCE_OCULUS;
+  return (display_id_ == device::mojom::XRDeviceId::OPENVR_DEVICE_ID)
+             ? GAMEPAD_SOURCE_OPENVR
+             : GAMEPAD_SOURCE_OCULUS;
 }
 
 void IsolatedGamepadDataFetcher::OnDataUpdated(
@@ -164,10 +166,10 @@
     // Gamepad extensions refer to display_id, corresponding to the WebVR
     // VRDisplay's dipslayId property.
     // As WebVR is deprecated, and we only hand out a maximum of one "display"
-    // per runtime, we use the VRDeviceId now to associate the controller with
+    // per runtime, we use the XRDeviceId now to associate the controller with
     // a headset.  This doesn't change behavior, but the device/display naming
     // could be confusing here.
-    if (display_id_ == VRDeviceId::OPENVR_DEVICE_ID) {
+    if (display_id_ == device::mojom::XRDeviceId::OPENVR_DEVICE_ID) {
       swprintf(dest.id, Gamepad::kIdLengthCap, L"OpenVR Gamepad");
     } else {
       if (dest.hand == GamepadHand::kLeft) {
@@ -198,4 +200,26 @@
 
 void IsolatedGamepadDataFetcher::OnAddedToProvider() {}
 
+void IsolatedGamepadDataFetcher::Factory::RemoveGamepad(
+    device::mojom::XRDeviceId id) {
+  using namespace device;
+  // TODO(crbug.com/868101) - Remove this.
+  std::map<device::mojom::XRDeviceId, GamepadSource>
+      device_id_to_gamepad_source = {
+          {device::mojom::XRDeviceId::OCULUS_DEVICE_ID, GAMEPAD_SOURCE_OCULUS},
+          {device::mojom::XRDeviceId::OPENVR_DEVICE_ID, GAMEPAD_SOURCE_OPENVR},
+      };
+
+  GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
+      device_id_to_gamepad_source[id]);
+}
+
+void IsolatedGamepadDataFetcher::Factory::AddGamepad(
+    device::mojom::XRDeviceId device_id,
+    device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory) {
+  device::GamepadDataFetcherManager::GetInstance()->AddFactory(
+      new device::IsolatedGamepadDataFetcher::Factory(
+          device_id, std::move(gamepad_factory)));
+}
+
 }  // namespace device
diff --git a/device/vr/isolated_gamepad_data_fetcher.h b/device/vr/isolated_gamepad_data_fetcher.h
index 8958b383..3951140 100644
--- a/device/vr/isolated_gamepad_data_fetcher.h
+++ b/device/vr/isolated_gamepad_data_fetcher.h
@@ -13,21 +13,26 @@
 
 class IsolatedGamepadDataFetcher : public GamepadDataFetcher {
  public:
-  class Factory : public GamepadDataFetcherFactory {
+  class DEVICE_VR_EXPORT Factory : public GamepadDataFetcherFactory {
    public:
-    Factory(VRDeviceId display_id,
+    Factory(device::mojom::XRDeviceId display_id,
             device::mojom::IsolatedXRGamepadProviderFactoryPtr factory);
     ~Factory() override;
     std::unique_ptr<GamepadDataFetcher> CreateDataFetcher() override;
     GamepadSource source() override;
 
+    static void AddGamepad(
+        device::mojom::XRDeviceId device_id,
+        device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory);
+    static void RemoveGamepad(device::mojom::XRDeviceId device_id);
+
    private:
-    VRDeviceId display_id_;
+    device::mojom::XRDeviceId display_id_;
     device::mojom::IsolatedXRGamepadProviderFactoryPtr factory_;
   };
 
   IsolatedGamepadDataFetcher(
-      VRDeviceId display_id,
+      device::mojom::XRDeviceId display_id,
       device::mojom::IsolatedXRGamepadProviderPtr provider);
   ~IsolatedGamepadDataFetcher() override;
 
@@ -40,7 +45,7 @@
   void OnDataUpdated(device::mojom::XRGamepadDataPtr data);
 
  private:
-  VRDeviceId display_id_;
+  device::mojom::XRDeviceId display_id_;
   bool have_outstanding_request_ = false;
   std::set<unsigned int> active_gamepads_;
   device::mojom::XRGamepadDataPtr data_;
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc
index da6a168..25cea45 100644
--- a/device/vr/oculus/oculus_device.cc
+++ b/device/vr/oculus/oculus_device.cc
@@ -48,10 +48,10 @@
   return eye_parameters;
 }
 
-mojom::VRDisplayInfoPtr CreateVRDisplayInfo(unsigned int id,
+mojom::VRDisplayInfoPtr CreateVRDisplayInfo(mojom::XRDeviceId id,
                                             ovrSession session) {
   mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New();
-  display_info->index = id;
+  display_info->id = id;
   display_info->displayName = std::string("Oculus");
   display_info->capabilities = mojom::VRDisplayCapabilities::New();
   display_info->capabilities->hasPosition = true;
@@ -84,7 +84,7 @@
 }  // namespace
 
 OculusDevice::OculusDevice()
-    : VRDeviceBase(VRDeviceId::OCULUS_DEVICE_ID),
+    : VRDeviceBase(mojom::XRDeviceId::OCULUS_DEVICE_ID),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       exclusive_controller_binding_(this),
       gamepad_provider_factory_binding_(this),
diff --git a/device/vr/oculus/oculus_device.h b/device/vr/oculus/oculus_device.h
index cefc6076..d60ae9c 100644
--- a/device/vr/oculus/oculus_device.h
+++ b/device/vr/oculus/oculus_device.h
@@ -18,9 +18,10 @@
 
 class OculusRenderLoop;
 
-class OculusDevice : public VRDeviceBase,
-                     public mojom::XRSessionController,
-                     public mojom::IsolatedXRGamepadProviderFactory {
+class DEVICE_VR_EXPORT OculusDevice
+    : public VRDeviceBase,
+      public mojom::XRSessionController,
+      public mojom::IsolatedXRGamepadProviderFactory {
  public:
   explicit OculusDevice();
   ~OculusDevice() override;
diff --git a/device/vr/oculus/oculus_device_provider.cc b/device/vr/oculus/oculus_device_provider.cc
index 0b8fa24f..b91253c 100644
--- a/device/vr/oculus/oculus_device_provider.cc
+++ b/device/vr/oculus/oculus_device_provider.cc
@@ -21,22 +21,24 @@
 }
 
 void OculusVRDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+        remove_device_callback,
     base::OnceClosure initialization_complete) {
   CreateDevice();
   if (device_) {
-    add_device_callback.Run(
-        static_cast<unsigned int>(VRDeviceId::OCULUS_DEVICE_ID),
-        device_->GetVRDisplayInfo(), device_->BindXRRuntimePtr());
+    add_device_callback.Run(device::mojom::XRDeviceId::OCULUS_DEVICE_ID,
+                            device_->GetVRDisplayInfo(),
+                            device_->BindXRRuntimePtr());
 
     // Removed in our destructor, as VRDeviceId::OCULUS_DEVICE_ID corresponds to
     // device::GAMEPAD_SOURCE_OCULUS.
     GamepadDataFetcherManager::GetInstance()->AddFactory(
-        new IsolatedGamepadDataFetcher::Factory(VRDeviceId::OCULUS_DEVICE_ID,
-                                                device_->BindGamepadFactory()));
+        new IsolatedGamepadDataFetcher::Factory(
+            device::mojom::XRDeviceId::OCULUS_DEVICE_ID,
+            device_->BindGamepadFactory()));
   }
   initialized_ = true;
   std::move(initialization_complete).Run();
diff --git a/device/vr/oculus/oculus_device_provider.h b/device/vr/oculus/oculus_device_provider.h
index 24791e1..6451c09e 100644
--- a/device/vr/oculus/oculus_device_provider.h
+++ b/device/vr/oculus/oculus_device_provider.h
@@ -12,8 +12,6 @@
 #include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_export.h"
 
-typedef struct ovrHmdStruct* ovrSession;
-
 namespace device {
 
 class OculusDevice;
@@ -24,10 +22,11 @@
   ~OculusVRDeviceProvider() override;
 
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+          remove_device_callback,
       base::OnceClosure initialization_complete) override;
 
   bool Initialized() override;
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index efd90999..28b5a88 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -62,9 +62,9 @@
 }
 
 mojom::VRDisplayInfoPtr CreateVRDisplayInfo(vr::IVRSystem* vr_system,
-                                            unsigned int id) {
+                                            device::mojom::XRDeviceId id) {
   mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New();
-  display_info->index = id;
+  display_info->id = id;
   display_info->displayName =
       GetOpenVRString(vr_system, vr::Prop_ManufacturerName_String) + " " +
       GetOpenVRString(vr_system, vr::Prop_ModelNumber_String);
@@ -128,7 +128,7 @@
 }  // namespace
 
 OpenVRDevice::OpenVRDevice()
-    : VRDeviceBase(VRDeviceId::OPENVR_DEVICE_ID),
+    : VRDeviceBase(device::mojom::XRDeviceId::OPENVR_DEVICE_ID),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       exclusive_controller_binding_(this),
       gamepad_provider_factory_binding_(this),
diff --git a/device/vr/openvr/openvr_device.h b/device/vr/openvr/openvr_device.h
index fea6cfb..61a7e618 100644
--- a/device/vr/openvr/openvr_device.h
+++ b/device/vr/openvr/openvr_device.h
@@ -18,9 +18,10 @@
 
 class OpenVRRenderLoop;
 
-class OpenVRDevice : public VRDeviceBase,
-                     public mojom::XRSessionController,
-                     public mojom::IsolatedXRGamepadProviderFactory {
+class DEVICE_VR_EXPORT OpenVRDevice
+    : public VRDeviceBase,
+      public mojom::XRSessionController,
+      public mojom::IsolatedXRGamepadProviderFactory {
  public:
   OpenVRDevice();
   ~OpenVRDevice() override;
diff --git a/device/vr/openvr/openvr_device_provider.cc b/device/vr/openvr/openvr_device_provider.cc
index bcb9cb8f..377eca334 100644
--- a/device/vr/openvr/openvr_device_provider.cc
+++ b/device/vr/openvr/openvr_device_provider.cc
@@ -37,10 +37,11 @@
 }
 
 void OpenVRDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+        remove_device_callback,
     base::OnceClosure initialization_complete) {
   CreateDevice();
   if (device_) {
@@ -62,8 +63,9 @@
   device_ = std::make_unique<OpenVRDevice>();
   if (device_->IsInitialized()) {
     GamepadDataFetcherManager::GetInstance()->AddFactory(
-        new IsolatedGamepadDataFetcher::Factory(VRDeviceId::OPENVR_DEVICE_ID,
-                                                device_->BindGamepadFactory()));
+        new IsolatedGamepadDataFetcher::Factory(
+            device::mojom::XRDeviceId::OPENVR_DEVICE_ID,
+            device_->BindGamepadFactory()));
   } else {
     device_ = nullptr;
   }
diff --git a/device/vr/openvr/openvr_device_provider.h b/device/vr/openvr/openvr_device_provider.h
index 7dc8229..ed9f4285 100644
--- a/device/vr/openvr/openvr_device_provider.h
+++ b/device/vr/openvr/openvr_device_provider.h
@@ -23,10 +23,11 @@
   ~OpenVRDeviceProvider() override;
 
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+          remove_device_callback,
       base::OnceClosure initialization_complete) override;
 
   bool Initialized() override;
diff --git a/device/vr/orientation/orientation_device.cc b/device/vr/orientation/orientation_device.cc
index d32cd63..e8b2067 100644
--- a/device/vr/orientation/orientation_device.cc
+++ b/device/vr/orientation/orientation_device.cc
@@ -23,11 +23,11 @@
 namespace {
 static constexpr int kDefaultPumpFrequencyHz = 60;
 
-mojom::VRDisplayInfoPtr CreateVRDisplayInfo(unsigned int id) {
+mojom::VRDisplayInfoPtr CreateVRDisplayInfo(mojom::XRDeviceId id) {
   static const char DEVICE_NAME[] = "VR Orientation Device";
 
   mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New();
-  display_info->index = id;
+  display_info->id = id;
   display_info->displayName = DEVICE_NAME;
   display_info->capabilities = mojom::VRDisplayCapabilities::New();
   display_info->capabilities->hasPosition = false;
@@ -52,7 +52,7 @@
 VROrientationDevice::VROrientationDevice(
     mojom::SensorProviderPtr* sensor_provider,
     base::OnceClosure ready_callback)
-    : VRDeviceBase(VRDeviceId::ORIENTATION_DEVICE_ID),
+    : VRDeviceBase(mojom::XRDeviceId::ORIENTATION_DEVICE_ID),
       ready_callback_(std::move(ready_callback)),
       binding_(this) {
   (*sensor_provider)
diff --git a/device/vr/orientation/orientation_device_provider.cc b/device/vr/orientation/orientation_device_provider.cc
index 7f327156..5cdf236 100644
--- a/device/vr/orientation/orientation_device_provider.cc
+++ b/device/vr/orientation/orientation_device_provider.cc
@@ -21,10 +21,10 @@
 VROrientationDeviceProvider::~VROrientationDeviceProvider() = default;
 
 void VROrientationDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
     base::OnceClosure initialization_complete) {
   if (device_ && device_->IsAvailable()) {
     add_device_callback.Run(device_->GetId(), device_->GetVRDisplayInfo(),
diff --git a/device/vr/orientation/orientation_device_provider.h b/device/vr/orientation/orientation_device_provider.h
index d7772325..a260c5b 100644
--- a/device/vr/orientation/orientation_device_provider.h
+++ b/device/vr/orientation/orientation_device_provider.h
@@ -24,10 +24,10 @@
   ~VROrientationDeviceProvider() override;
 
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
       base::OnceClosure initialization_complete) override;
 
   bool Initialized() override;
@@ -42,7 +42,7 @@
   std::unique_ptr<VROrientationDevice> device_;
 
   base::RepeatingCallback<
-      void(unsigned int, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)>
+      void(mojom::XRDeviceId, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)>
       add_device_callback_;
   base::OnceClosure initialized_callback_;
 
diff --git a/device/vr/orientation/orientation_device_provider_unittest.cc b/device/vr/orientation/orientation_device_provider_unittest.cc
index bccfdc3..2909230 100644
--- a/device/vr/orientation/orientation_device_provider_unittest.cc
+++ b/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -83,22 +83,26 @@
     return init_params;
   }
 
-  base::RepeatingCallback<
-      void(unsigned int, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr device)>
+  base::RepeatingCallback<void(device::mojom::XRDeviceId,
+                               mojom::VRDisplayInfoPtr,
+                               mojom::XRRuntimePtr device)>
   DeviceAndIdCallbackFailIfCalled() {
-    return base::BindRepeating([](unsigned int id, mojom::VRDisplayInfoPtr,
+    return base::BindRepeating([](device::mojom::XRDeviceId id,
+                                  mojom::VRDisplayInfoPtr,
                                   mojom::XRRuntimePtr device) { FAIL(); });
   };
 
-  base::RepeatingCallback<void(unsigned int)> DeviceIdCallbackFailIfCalled() {
-    return base::BindRepeating([](unsigned int id) { FAIL(); });
+  base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+  DeviceIdCallbackFailIfCalled() {
+    return base::BindRepeating([](device::mojom::XRDeviceId id) { FAIL(); });
   };
 
-  base::RepeatingCallback<
-      void(unsigned int, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr device)>
+  base::RepeatingCallback<void(device::mojom::XRDeviceId,
+                               mojom::VRDisplayInfoPtr,
+                               mojom::XRRuntimePtr device)>
   DeviceAndIdCallbackMustBeCalled(base::RunLoop* loop) {
     return base::BindRepeating(
-        [](base::OnceClosure quit_closure, unsigned int id,
+        [](base::OnceClosure quit_closure, device::mojom::XRDeviceId id,
            mojom::VRDisplayInfoPtr info, mojom::XRRuntimePtr device) {
           ASSERT_TRUE(device);
           ASSERT_TRUE(info);
@@ -107,10 +111,10 @@
         loop->QuitClosure());
   };
 
-  base::RepeatingCallback<void(unsigned int)> DeviceIdCallbackMustBeCalled(
-      base::RunLoop* loop) {
+  base::RepeatingCallback<void(device::mojom::XRDeviceId)>
+  DeviceIdCallbackMustBeCalled(base::RunLoop* loop) {
     return base::BindRepeating(
-        [](base::OnceClosure quit_closure, unsigned int id) {
+        [](base::OnceClosure quit_closure, device::mojom::XRDeviceId id) {
           std::move(quit_closure).Run();
         },
         loop->QuitClosure());
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index 9366552..9666ddcd 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -6,6 +6,8 @@
 
 import "device/vr/public/mojom/vr_service.mojom";
 
+const string kVrIsolatedServiceName = "xr_device_service";
+
 // The XRSessionController lives in the vr device service, and corresponds to
 // a set of the XRSession bindings.  The client is the browser process, which
 // will pause or stop sessions depending events/state such as focus or other
@@ -132,3 +134,34 @@
   // browser process).
   GetIsolatedXRGamepadProvider(IsolatedXRGamepadProvider& provider);
 };
+
+// Notify the browser process about a set of runtimes.  The browser process
+// implements this interface to be notified about runtime changes from the XR
+// device service.
+interface IsolatedXRRuntimeProviderClient {
+  // Called when runtimes are initially enumerated, or when devices are later
+  // attached and become available.
+  OnDeviceAdded(XRRuntime runtime,
+      IsolatedXRGamepadProviderFactory gamepad_factory,
+      device.mojom.VRDisplayInfo display_info);
+
+  // Called when runtimes become unavailable - for example if the hardware is
+  // disconnected or the APIs notify us that they are shutting down.
+  // device_index corresponds to display_info->index for a previously added
+  // device.
+  OnDeviceRemoved(device.mojom.XRDeviceId device_index);
+
+  // Called once after all the initial OnDeviceAdded calls are completed.
+  // This is a signal to the browser that it knows what hardware is available,
+  // and can unblock any callbacks/promises that WebXR APIs are blocked.
+  OnDevicesEnumerated();
+};
+
+// Provides access to XRRuntimes.  This is implemented in the XR device service,
+// and consumed by the browser.
+interface IsolatedXRRuntimeProvider {
+  // Register a client, and triggers OnDeviceAdded for all available runtimes,
+  // followed by OnDevicesEnumerated.
+  // Should only be called once.
+  RequestDevices(IsolatedXRRuntimeProviderClient client);
+};
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom
index eb75e876..f0faf52 100644
--- a/device/vr/public/mojom/vr_service.mojom
+++ b/device/vr/public/mojom/vr_service.mojom
@@ -16,6 +16,19 @@
 // WebXR interfaces
 //
 
+// TODO: Use EnableIf to only define values on platforms that have
+// implementations.
+enum XRDeviceId {
+  LAYOUT_TEST_DEVICE_ID = 0, // Fake device used by layout tests.
+  GVR_DEVICE_ID = 1,
+  OPENVR_DEVICE_ID = 2,
+  OCULUS_DEVICE_ID = 3,
+  ARCORE_DEVICE_ID = 4,
+  ORIENTATION_DEVICE_ID = 5,
+  FAKE_DEVICE_ID = 6, // Fake device used by unit tests.
+};
+
+
 enum XRHandedness {
   NONE = 0,
   LEFT = 1,
@@ -166,7 +179,7 @@
 };
 
 struct VRDisplayInfo {
-  uint32 index;
+  XRDeviceId id;
   string displayName;
   VRDisplayCapabilities capabilities;
   VRStageParameters? stageParameters;
diff --git a/device/vr/test/fake_vr_device.cc b/device/vr/test/fake_vr_device.cc
index ba0baf3a..eeaafc65 100644
--- a/device/vr/test/fake_vr_device.cc
+++ b/device/vr/test/fake_vr_device.cc
@@ -6,8 +6,8 @@
 
 namespace device {
 
-FakeVRDevice::FakeVRDevice(unsigned int id)
-    : VRDeviceBase(static_cast<VRDeviceId>(id)), controller_binding_(this) {
+FakeVRDevice::FakeVRDevice(mojom::XRDeviceId id)
+    : VRDeviceBase(id), controller_binding_(this) {
   SetVRDisplayInfo(InitBasicDevice());
 }
 
@@ -15,7 +15,7 @@
 
 mojom::VRDisplayInfoPtr FakeVRDevice::InitBasicDevice() {
   mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New();
-  display_info->index = GetId();
+  display_info->id = GetId();
   display_info->displayName = "FakeVRDevice";
 
   display_info->capabilities = mojom::VRDisplayCapabilities::New();
diff --git a/device/vr/test/fake_vr_device.h b/device/vr/test/fake_vr_device.h
index fc1aa6f..a1ed5d6 100644
--- a/device/vr/test/fake_vr_device.h
+++ b/device/vr/test/fake_vr_device.h
@@ -17,7 +17,7 @@
 class DEVICE_VR_EXPORT FakeVRDevice : public VRDeviceBase,
                                       public mojom::XRSessionController {
  public:
-  FakeVRDevice(unsigned int id);
+  explicit FakeVRDevice(mojom::XRDeviceId id);
   ~FakeVRDevice() override;
 
   void RequestSession(
diff --git a/device/vr/test/fake_vr_device_provider.cc b/device/vr/test/fake_vr_device_provider.cc
index dc4d097..567775b 100644
--- a/device/vr/test/fake_vr_device_provider.cc
+++ b/device/vr/test/fake_vr_device_provider.cc
@@ -22,7 +22,7 @@
                              device_base->BindXRRuntimePtr());
 }
 
-void FakeVRDeviceProvider::RemoveDevice(unsigned int device_id) {
+void FakeVRDeviceProvider::RemoveDevice(mojom::XRDeviceId device_id) {
   auto it = std::find_if(
       devices_.begin(), devices_.end(),
       [device_id](const std::unique_ptr<VRDeviceBase>& device) {
@@ -34,10 +34,10 @@
 }
 
 void FakeVRDeviceProvider::Initialize(
-    base::RepeatingCallback<void(unsigned int,
+    base::RepeatingCallback<void(mojom::XRDeviceId,
                                  mojom::VRDisplayInfoPtr,
                                  mojom::XRRuntimePtr)> add_device_callback,
-    base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+    base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
     base::OnceClosure initialization_complete) {
   add_device_callback_ = std::move(add_device_callback);
   remove_device_callback_ = std::move(remove_device_callback);
diff --git a/device/vr/test/fake_vr_device_provider.h b/device/vr/test/fake_vr_device_provider.h
index 81924fa..a5e5602 100644
--- a/device/vr/test/fake_vr_device_provider.h
+++ b/device/vr/test/fake_vr_device_provider.h
@@ -22,13 +22,13 @@
   // Adds devices to the provider with the given device, which will be
   // returned when GetDevices is queried.
   void AddDevice(std::unique_ptr<VRDeviceBase> device);
-  void RemoveDevice(unsigned int device_id);
+  void RemoveDevice(mojom::XRDeviceId device_id);
 
   void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(mojom::XRDeviceId,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
       base::OnceClosure initialization_complete) override;
   bool Initialized() override;
 
@@ -36,9 +36,9 @@
   std::vector<std::unique_ptr<VRDeviceBase>> devices_;
   bool initialized_;
   base::RepeatingCallback<
-      void(unsigned int, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)>
+      void(mojom::XRDeviceId, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)>
       add_device_callback_;
-  base::RepeatingCallback<void(unsigned int)> remove_device_callback_;
+  base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeVRDeviceProvider);
 };
diff --git a/device/vr/test/fake_vr_display_impl_client.cc b/device/vr/test/fake_vr_display_impl_client.cc
index c263a433..94f13e2e 100644
--- a/device/vr/test/fake_vr_display_impl_client.cc
+++ b/device/vr/test/fake_vr_display_impl_client.cc
@@ -19,7 +19,7 @@
 }
 
 void FakeVRDisplayImplClient::OnChanged(mojom::VRDisplayInfoPtr display) {
-  service_client_->SetLastDeviceId(display->index);
+  service_client_->SetLastDeviceId(display->id);
 }
 
 }  // namespace device
diff --git a/device/vr/test/fake_vr_service_client.cc b/device/vr/test/fake_vr_service_client.cc
index 7cb9183..0fcb1dd 100644
--- a/device/vr/test/fake_vr_service_client.cc
+++ b/device/vr/test/fake_vr_service_client.cc
@@ -24,11 +24,11 @@
   display_clients_.push_back(std::move(display_client));
 }
 
-void FakeVRServiceClient::SetLastDeviceId(unsigned int id) {
+void FakeVRServiceClient::SetLastDeviceId(mojom::XRDeviceId id) {
   last_device_id_ = id;
 }
 
-bool FakeVRServiceClient::CheckDeviceId(unsigned int id) {
+bool FakeVRServiceClient::CheckDeviceId(mojom::XRDeviceId id) {
   return id == last_device_id_;
 }
 
diff --git a/device/vr/test/fake_vr_service_client.h b/device/vr/test/fake_vr_service_client.h
index 62d5d70..c0905ee 100644
--- a/device/vr/test/fake_vr_service_client.h
+++ b/device/vr/test/fake_vr_service_client.h
@@ -22,13 +22,13 @@
   void OnDisplayConnected(mojom::XRDevicePtr device,
                           mojom::VRDisplayClientRequest request,
                           mojom::VRDisplayInfoPtr displayInfo) override;
-  void SetLastDeviceId(unsigned int id);
-  bool CheckDeviceId(unsigned int id);
+  void SetLastDeviceId(mojom::XRDeviceId id);
+  bool CheckDeviceId(mojom::XRDeviceId id);
 
  private:
   std::vector<mojom::VRDisplayInfoPtr> displays_;
   std::vector<std::unique_ptr<FakeVRDisplayImplClient>> display_clients_;
-  unsigned int last_device_id_ = 0;
+  mojom::XRDeviceId last_device_id_ = static_cast<mojom::XRDeviceId>(0);
   mojo::Binding<mojom::VRServiceClient> m_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeVRServiceClient);
diff --git a/device/vr/vr_device.h b/device/vr/vr_device.h
index aaa2294f..abc3dff 100644
--- a/device/vr/vr_device.h
+++ b/device/vr/vr_device.h
@@ -27,16 +27,6 @@
   VIEWER_TYPE_COUNT,
 };
 
-// Hardcoded list of ids for each device type.
-enum class VRDeviceId : unsigned int {
-  GVR_DEVICE_ID = 1,
-  OPENVR_DEVICE_ID = 2,
-  OCULUS_DEVICE_ID = 3,
-  ARCORE_DEVICE_ID = 4,
-  ORIENTATION_DEVICE_ID = 5,
-  FAKE_DEVICE_ID = 6,
-};
-
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 enum class XrRuntimeAvailable {
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc
index d5f3e5f..87e4b8e 100644
--- a/device/vr/vr_device_base.cc
+++ b/device/vr/vr_device_base.cc
@@ -9,12 +9,12 @@
 
 namespace device {
 
-VRDeviceBase::VRDeviceBase(VRDeviceId id)
-    : id_(static_cast<unsigned int>(id)), runtime_binding_(this) {}
+VRDeviceBase::VRDeviceBase(mojom::XRDeviceId id)
+    : id_(id), runtime_binding_(this) {}
 
 VRDeviceBase::~VRDeviceBase() = default;
 
-unsigned int VRDeviceBase::GetId() const {
+mojom::XRDeviceId VRDeviceBase::GetId() const {
   return id_;
 }
 
@@ -64,7 +64,7 @@
 
 void VRDeviceBase::SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info) {
   DCHECK(display_info);
-  DCHECK(display_info->index == id_);
+  DCHECK(display_info->id == id_);
   bool initialized = !!display_info_;
   display_info_ = std::move(display_info);
 
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h
index 230a0acf..93ec057 100644
--- a/device/vr/vr_device_base.h
+++ b/device/vr/vr_device_base.h
@@ -22,7 +22,7 @@
 // TODO(mthiesse, crbug.com/769373): Remove DEVICE_VR_EXPORT.
 class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
  public:
-  explicit VRDeviceBase(VRDeviceId id);
+  explicit VRDeviceBase(mojom::XRDeviceId id);
   ~VRDeviceBase() override;
 
   // VRDevice Implementation
@@ -36,7 +36,7 @@
   virtual void RequestHitTest(
       mojom::XRRayPtr ray,
       mojom::XREnviromentIntegrationProvider::RequestHitTestCallback callback);
-  unsigned int GetId() const;
+  device::mojom::XRDeviceId GetId() const;
 
   bool HasExclusiveSession();
   void EndMagicWindowSession(VRDisplayImpl* session);
@@ -91,7 +91,7 @@
 
   bool presenting_ = false;
 
-  unsigned int id_;
+  device::mojom::XRDeviceId id_;
   bool magic_window_enabled_ = true;
 
   mojo::Binding<mojom::XRRuntime> runtime_binding_;
diff --git a/device/vr/vr_device_base_unittest.cc b/device/vr/vr_device_base_unittest.cc
index 6eb9f45..318b292 100644
--- a/device/vr/vr_device_base_unittest.cc
+++ b/device/vr/vr_device_base_unittest.cc
@@ -21,7 +21,7 @@
 
 class VRDeviceBaseForTesting : public VRDeviceBase {
  public:
-  VRDeviceBaseForTesting() : VRDeviceBase(VRDeviceId::FAKE_DEVICE_ID) {}
+  VRDeviceBaseForTesting() : VRDeviceBase(mojom::XRDeviceId::FAKE_DEVICE_ID) {}
   ~VRDeviceBaseForTesting() override = default;
 
   void SetVRDisplayInfoForTest(mojom::VRDisplayInfoPtr display_info) {
@@ -102,9 +102,9 @@
     return device;
   }
 
-  mojom::VRDisplayInfoPtr MakeVRDisplayInfo(unsigned int device_id) {
+  mojom::VRDisplayInfoPtr MakeVRDisplayInfo(mojom::XRDeviceId device_id) {
     mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New();
-    display_info->index = device_id;
+    display_info->id = device_id;
     display_info->capabilities = mojom::VRDisplayCapabilities::New();
     return display_info;
   }
@@ -150,7 +150,8 @@
 }
 
 TEST_F(VRDeviceTest, NoMagicWindowPosesWhileBrowsing) {
-  auto device = std::make_unique<FakeVRDevice>(1);
+  auto device =
+      std::make_unique<FakeVRDevice>(static_cast<device::mojom::XRDeviceId>(1));
   device->SetPose(mojom::VRPose::New());
 
   device->GetFrameData(base::BindOnce(
diff --git a/device/vr/vr_device_provider.h b/device/vr/vr_device_provider.h
index 26732491..27616ca 100644
--- a/device/vr/vr_device_provider.h
+++ b/device/vr/vr_device_provider.h
@@ -19,10 +19,11 @@
 
   // If the VR API requires initialization that should happen here.
   virtual void Initialize(
-      base::RepeatingCallback<void(unsigned int,
+      base::RepeatingCallback<void(mojom::XRDeviceId id,
                                    mojom::VRDisplayInfoPtr,
                                    mojom::XRRuntimePtr)> add_device_callback,
-      base::RepeatingCallback<void(unsigned int)> remove_device_callback,
+      base::RepeatingCallback<void(mojom::XRDeviceId id)>
+          remove_device_callback,
       base::OnceClosure initialization_complete) = 0;
 
   // Returns true if initialization is complete.
diff --git a/device/vr/vr_display_impl_unittest.cc b/device/vr/vr_display_impl_unittest.cc
index f6d4b1a..c568c97 100644
--- a/device/vr/vr_display_impl_unittest.cc
+++ b/device/vr/vr_display_impl_unittest.cc
@@ -24,7 +24,7 @@
 
  protected:
   void SetUp() override {
-    device_ = std::make_unique<FakeVRDevice>(1);
+    device_ = std::make_unique<FakeVRDevice>(static_cast<mojom::XRDeviceId>(1));
     device_->SetPose(mojom::VRPose::New());
     mojom::VRServiceClientPtr proxy;
     client_ = std::make_unique<FakeVRServiceClient>(mojo::MakeRequest(&proxy));
diff --git a/docs/updating_clang.md b/docs/updating_clang.md
index b0e3041..594fb39 100644
--- a/docs/updating_clang.md
+++ b/docs/updating_clang.md
@@ -18,6 +18,8 @@
             gs://chromium-browser-clang/$x/llvmobjdump-$rev.tgz ; \
         gsutil.py cp -n -a public-read gs://chromium-browser-clang-staging/$x/llvmcfiverify-$rev.tgz \
             gs://chromium-browser-clang/$x/llvmcfiverify-$rev.tgz ; \
+        gsutil.py cp -n -a public-read gs://chromium-browser-clang-staging/$x/safestack-$rev.tgz \
+            gs://chromium-browser-clang/$x/safestack-$rev.tgz ; \
         gsutil.py cp -n -a public-read gs://chromium-browser-clang-staging/$x/translation_unit-$rev.tgz \
             gs://chromium-browser-clang/$x/translation_unit-$rev.tgz ; \
         gsutil.py cp -n -a public-read gs://chromium-browser-clang-staging/$x/llvm-code-coverage-$rev.tgz \
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 15011a3..ba2df9d 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -238,7 +238,7 @@
     "//extensions/test/data/",
     "//net/tools/testserver/",
     "//third_party/pyftpdlib/",
-    "//third_party/pywebsocket/",
+    "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
     "$root_out_dir/extensions_shell_and_test.pak",
   ]
diff --git a/extensions/browser/updater/update_service.cc b/extensions/browser/updater/update_service.cc
index 93dda0f4..df22e6a 100644
--- a/extensions/browser/updater/update_service.cc
+++ b/extensions/browser/updater/update_service.cc
@@ -136,11 +136,18 @@
       complete_event = true;
       finish_delayed_installation = true;
       {
+        update_client::ErrorCategory error_category =
+            update_client::ErrorCategory::kNone;
         update_client::CrxUpdateItem update_item;
-        if (!update_client_->GetCrxUpdateState(extension_id, &update_item)) {
-          NOTREACHED();
+        if (update_client_->GetCrxUpdateState(extension_id, &update_item)) {
+          // When update_client_->GetCrxUpdateState(...) returns false, it means
+          // that |update_client_| can't find any information about this
+          // |extension_id|. It could be possible that |extension_id| was
+          // uninstalled when |update_client_| was checking for updates.
+          // (see bug http://crbug.com/869663).
+          error_category = update_item.error_category;
         }
-        switch (update_item.error_category) {
+        switch (error_category) {
           case update_client::ErrorCategory::kUpdateCheck:
             ReportUpdateCheckResult(
                 ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR,
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index fbdd8920..fe678ee3 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -432,7 +432,9 @@
       "96FF2FFA5C9173C76D47184B3E86D267B37781DE",  // http://crbug.com/642141
       "0136FCB13DB29FD5CD442F56E59E53B61F1DF96F",  // http://crbug.com/642141
       "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F",  // PDF Viewer
-      "75C7F4B720314B6CB1B5817CD86089DB95CD2461"   // Chromevox on chromecast
+      "75C7F4B720314B6CB1B5817CD86089DB95CD2461",  // Chromevox on chromecast
+      "46578A13607D38F1DC8E280C4F499FB0A2F9565C",  // http://crbug.com/819404
+      "898FB5A39687D210766B8998BA4530B99C9E6586"   // http://crbug.com/819404
     ]
   },
   "nativeMessaging": {
@@ -611,7 +613,7 @@
     }
   ],
   "system.powerSource": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["platform_app"],
     "platforms": ["chromeos"],
     "session_types": ["kiosk"]
diff --git a/extensions/test/data/web_view/apitest/main.js b/extensions/test/data/web_view/apitest/main.js
index 56174c5..cb90671 100644
--- a/extensions/test/data/web_view/apitest/main.js
+++ b/extensions/test/data/web_view/apitest/main.js
@@ -1673,25 +1673,35 @@
   }, requestFilter, extraInfoSpec);
 
   var loadstartCalled = false;
-  webview.addEventListener('loadstart', function(e) {
-    embedder.test.assertTrue(e.isTopLevel);
-    embedder.test.assertEq(embedder.detectUserAgentURL, e.url);
-    loadstartCalled = true;
-  });
 
-  webview.addEventListener('loadredirect', function(e) {
-    embedder.test.assertTrue(e.isTopLevel);
-    embedder.test.assertEq(embedder.detectUserAgentURL,
-        e.oldUrl.replace('127.0.0.1', 'localhost'));
-    embedder.test.assertEq(embedder.redirectGuestURLDest,
-        e.newUrl.replace('127.0.0.1', 'localhost'));
-    if (loadstartCalled) {
-      embedder.test.succeed();
-    } else {
-      embedder.test.fail();
-    }
-  });
-  webview.src = embedder.detectUserAgentURL;
+  var listener = function() {
+    webview.removeEventListener('loadstop', listener);
+    // Now load the real URL for the test.
+    webview.src = embedder.detectUserAgentURL;
+
+    webview.addEventListener('loadstart', function(e) {
+      embedder.test.assertTrue(e.isTopLevel);
+      embedder.test.assertEq(embedder.detectUserAgentURL, e.url);
+      loadstartCalled = true;
+    });
+
+    webview.addEventListener('loadredirect', function(e) {
+      embedder.test.assertTrue(e.isTopLevel);
+      embedder.test.assertEq(embedder.detectUserAgentURL,
+          e.oldUrl.replace('127.0.0.1', 'localhost'));
+      embedder.test.assertEq(embedder.redirectGuestURLDest,
+          e.newUrl.replace('127.0.0.1', 'localhost'));
+      if (loadstartCalled) {
+        embedder.test.succeed();
+      } else {
+        embedder.test.fail();
+      }
+    });
+  };
+  webview.addEventListener('loadstop', listener);
+
+  // Load an empty URL to wait for the webRequest listener to be set up.
+  webview.src = embedder.emptyGuestURL;
   document.body.appendChild(webview);
 }
 
diff --git a/gpu/DEPS b/gpu/DEPS
index 0273fe3..020fd3a 100644
--- a/gpu/DEPS
+++ b/gpu/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+third_party/angle",
   "+third_party/amd",
+  "+third_party/nvml",
   "+third_party/re2",
   "+third_party/smhasher",
   "+third_party/swiftshader",
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index a595002..47f44e86 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -168,6 +168,12 @@
       "setupapi.lib",
     ]
 
+    sources += [
+      "//third_party/nvml/nvml.h",
+      "nvml_info.cc",
+      "nvml_info.h",
+    ]
+
     if (is_chrome_branded && is_official_build) {
       sources += [
         "//third_party/amd/AmdCfxPxExt.h",
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index d08fb7e..d52450d 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -489,7 +489,7 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "<=",
-        "value": "8.17.12.6973"
+        "value": "269.73"
       },
       "features": [
         "disable_d3d11"
@@ -1850,7 +1850,7 @@
       },
       "driver_version": {
         "op": "<",
-        "value": "21.21.13.7576"
+        "value": "375.76"
       },
       "vendor_id": "0x10de",
       "features": [
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index ca66ab08..1de8bed3 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -19,6 +19,8 @@
   enumerator->AddString("driverVendor", device.driver_vendor);
   enumerator->AddString("driverVersion", device.driver_version);
   enumerator->AddString("driverDate", device.driver_date);
+  enumerator->AddInt("cudaComputeCapabilityMajor",
+                     device.cuda_compute_capability_major);
   enumerator->EndGPUDevice();
 }
 
@@ -94,8 +96,8 @@
 GPUInfo::GPUDevice::GPUDevice()
     : vendor_id(0),
       device_id(0),
-      active(false) {
-}
+      active(false),
+      cuda_compute_capability_major(0) {}
 
 GPUInfo::GPUDevice::GPUDevice(const GPUInfo::GPUDevice& other) = default;
 
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index e367ee0..21c70eb 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -137,6 +137,10 @@
     std::string driver_vendor;
     std::string driver_version;
     std::string driver_date;
+
+    // NVIDIA CUDA compute capability, major version. 0 if undetermined. Can be
+    // used to determine the hardware generation that the GPU belongs to.
+    int cuda_compute_capability_major;
   };
 
   GPUInfo();
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index 0bfcff229..41a2834 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -36,6 +36,7 @@
 #include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/scoped_com_initializer.h"
+#include "gpu/config/nvml_info.h"
 #include "third_party/vulkan/include/vulkan/vulkan.h"
 
 namespace gpu {
@@ -124,6 +125,28 @@
 }
 #endif
 
+std::string ParseNVIDIARegistryDriverVersion(std::string registry_version) {
+  // The NVIDIA driver version in the registry is most commonly in the format:
+  // XX.XX.XD.DDDD
+  // Where "X" corresponds to an OS-specific digit and "D" corresponds to a
+  // digit of the actual driver version. We convert it to the following format:
+  // DDD.DD
+  // This matches with the actual driver version that NVML also returns.
+  std::string second_to_last_digits;
+  std::string last_digits;
+  if (!RE2::FullMatch(registry_version, "\\d+\\.\\d+\\.(\\d+)\\.(\\d+)",
+                      &second_to_last_digits, &last_digits)) {
+    return registry_version;
+  }
+  std::string digits = second_to_last_digits + last_digits;
+  if (digits.length() < 5u) {
+    return registry_version;
+  }
+  digits.erase(0, digits.length() - 5u);
+  DCHECK(digits.length() == 5u);
+  return digits.substr(0u, 3u) + "." + digits.substr(3u);
+}
+
 bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
   TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
 
@@ -199,6 +222,28 @@
             found_intel = true;
           if (device.vendor_id == 0x1002)
             found_amd = true;
+          if (device.vendor_id == 0x10de) {
+            std::string nvml_driver_version;
+            int major_cuda_compute_capability = 0;
+            int minor_cuda_compute_capability = 0;
+            bool nvml_success = GetNvmlDeviceInfo(
+                device.device_id, &nvml_driver_version,
+                &major_cuda_compute_capability, &minor_cuda_compute_capability);
+            if (nvml_success) {
+              // We use the NVML driver version instead of the registry version,
+              // since the registry version includes OS-specific digits that are
+              // not part of the actual driver version.
+              device.driver_version = nvml_driver_version;
+              device.cuda_compute_capability_major =
+                  major_cuda_compute_capability;
+            } else {
+              // If we can't get the actual driver version from NVML, do
+              // best-effort parsing of the actual driver version from the
+              // registry driver version.
+              device.driver_version =
+                  ParseNVIDIARegistryDriverVersion(device.driver_version);
+            }
+          }
           devices.push_back(device);
         }
 
diff --git a/gpu/config/nvml_info.cc b/gpu/config/nvml_info.cc
new file mode 100644
index 0000000..521aa5b
--- /dev/null
+++ b/gpu/config/nvml_info.cc
@@ -0,0 +1,126 @@
+// 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/config/nvml_info.h"
+
+#include <windows.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "third_party/nvml/nvml.h"
+
+namespace {
+
+const unsigned int kDriverVersionCapacity = 80u;
+
+}  // anonymous namespace
+
+typedef decltype(&nvmlInit) INITPROC;
+typedef decltype(&nvmlShutdown) SHUTDOWNPROC;
+typedef decltype(&nvmlSystemGetDriverVersion) GETDRIVERVERSIONPROC;
+typedef decltype(&nvmlDeviceGetCount) DEVICEGETCOUNTPROC;
+typedef decltype(&nvmlDeviceGetHandleByIndex) DEVICEGETHANDLEBYINDEXPROC;
+typedef decltype(&nvmlDeviceGetPciInfo) DEVICEGETPCIINFOPROC;
+typedef decltype(
+    &nvmlDeviceGetCudaComputeCapability) DEVICEGETCUDACOMPUTECAPABILITYPROC;
+
+bool GetNvmlDeviceInfo(uint32_t pci_device_id,
+                       std::string* driver_version,
+                       int* major_cuda_compute_capability,
+                       int* minor_cuda_compute_capability) {
+  DCHECK(major_cuda_compute_capability);
+  DCHECK(minor_cuda_compute_capability);
+  *major_cuda_compute_capability = 0;
+  *minor_cuda_compute_capability = 0;
+
+  base::FilePath dll_path;
+  if (!base::PathService::Get(base::DIR_PROGRAM_FILES6432, &dll_path)) {
+    return false;
+  }
+  dll_path = dll_path.Append(L"NVIDIA Corporation\\NVSMI\\nvml.dll");
+  HINSTANCE hinstNVML = LoadLibrary(dll_path.value().data());
+
+  if (!hinstNVML) {
+    return false;
+  }
+
+  INITPROC fnNvmlInit = (INITPROC)GetProcAddress(hinstNVML, "nvmlInit");
+  SHUTDOWNPROC fnNvmlShutdown =
+      (SHUTDOWNPROC)GetProcAddress(hinstNVML, "nvmlShutdown");
+  GETDRIVERVERSIONPROC fnNvmlSystemGetDriverVersion =
+      (GETDRIVERVERSIONPROC)GetProcAddress(hinstNVML,
+                                           "nvmlSystemGetDriverVersion");
+  DEVICEGETCOUNTPROC fnNvmlDeviceGetCount =
+      (DEVICEGETCOUNTPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetCount");
+  DEVICEGETHANDLEBYINDEXPROC fnNvmlDeviceGetHandleByIndex =
+      (DEVICEGETHANDLEBYINDEXPROC)GetProcAddress(hinstNVML,
+                                                 "nvmlDeviceGetHandleByIndex");
+  DEVICEGETPCIINFOPROC fnNvmlDeviceGetPciInfo =
+      (DEVICEGETPCIINFOPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetPciInfo");
+  DEVICEGETCUDACOMPUTECAPABILITYPROC fnNvmlDeviceGetCudaComputeCapability =
+      (DEVICEGETCUDACOMPUTECAPABILITYPROC)GetProcAddress(
+          hinstNVML, "nvmlDeviceGetCudaComputeCapability");
+
+  if (!fnNvmlInit || !fnNvmlShutdown || !fnNvmlSystemGetDriverVersion) {
+    return false;
+  }
+
+  nvmlReturn_t result = fnNvmlInit();
+  if (NVML_SUCCESS != result) {
+    return false;
+  }
+
+  char driver_version_temp[kDriverVersionCapacity];
+
+  result =
+      fnNvmlSystemGetDriverVersion(driver_version_temp, kDriverVersionCapacity);
+  if (NVML_SUCCESS != result) {
+    fnNvmlShutdown();
+    return false;
+  }
+
+  *driver_version = driver_version_temp;
+
+  if (fnNvmlDeviceGetCount && fnNvmlDeviceGetHandleByIndex &&
+      fnNvmlDeviceGetPciInfo && fnNvmlDeviceGetCudaComputeCapability) {
+    unsigned int device_count;
+    result = fnNvmlDeviceGetCount(&device_count);
+    if (NVML_SUCCESS == result) {
+      for (unsigned int i = 0; i < device_count; i++) {
+        nvmlDevice_t device;
+        nvmlPciInfo_t pci;
+
+        result = fnNvmlDeviceGetHandleByIndex(i, &device);
+        if (NVML_SUCCESS != result) {
+          continue;
+        }
+
+        result = fnNvmlDeviceGetPciInfo(device, &pci);
+        if (NVML_SUCCESS != result) {
+          continue;
+        }
+
+        // We're looking for a particular PCI device.
+        if (pci.pciDeviceId != ((pci_device_id << 16) | 0x10deu)) {
+          continue;
+        }
+
+        result = fnNvmlDeviceGetCudaComputeCapability(
+            device, major_cuda_compute_capability,
+            minor_cuda_compute_capability);
+        if (NVML_SUCCESS != result) {
+          *major_cuda_compute_capability = 0;
+          *minor_cuda_compute_capability = 0;
+        }
+      }
+    }
+  }
+
+  result = fnNvmlShutdown();
+  if (NVML_SUCCESS != result) {
+    return false;
+  }
+  return true;
+}
diff --git a/gpu/config/nvml_info.h b/gpu/config/nvml_info.h
new file mode 100644
index 0000000..e1f0f51
--- /dev/null
+++ b/gpu/config/nvml_info.h
@@ -0,0 +1,22 @@
+// 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_CONFIG_NVML_INFO_H_
+#define GPU_CONFIG_NVML_INFO_H_
+
+#include "build/build_config.h"
+
+#include <stdint.h>
+#include <string>
+
+// Queries driver version and places it into driver_version. Writes
+// major_cuda_compute_capability and minor_cuda_compute_capability of the GPU
+// matching pci_device_id if one is found, or writes 0 into these outputs
+// otherwise. Returns true on success.
+bool GetNvmlDeviceInfo(uint32_t pci_device_id,
+                       std::string* driver_version,
+                       int* major_cuda_compute_capability,
+                       int* minor_cuda_compute_capability);
+
+#endif  // GPU_CONFIG_NVML_INFO_H_
\ No newline at end of file
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index 2f689306..d472340a 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -448,7 +448,7 @@
     },
     {
       "id": 59,
-      "description": "NVidia driver 8.15.11.8593 is crashy on Windows",
+      "description": "NVidia driver 185.93 is crashy on Windows",
       "cr_bugs": [155749],
       "os": {
         "type": "win"
@@ -456,7 +456,7 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "=",
-        "value": "8.15.11.8593"
+        "value": "185.93"
       },
       "features": [
         "accelerated_video_decode"
@@ -499,7 +499,7 @@
     },
     {
       "id": 69,
-      "description": "NVIDIA driver 8.17.11.9621 is buggy with Stage3D baseline mode",
+      "description": "NVIDIA driver 196.21 is buggy with Stage3D baseline mode",
       "cr_bugs": [172771],
       "os": {
         "type": "win"
@@ -507,7 +507,7 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "=",
-        "value": "8.17.11.9621"
+        "value": "196.21"
       },
       "features": [
         "flash_stage3d_baseline"
@@ -515,7 +515,7 @@
     },
     {
       "id": 70,
-      "description": "NVIDIA driver 8.17.11.8267 is buggy with Stage3D baseline mode",
+      "description": "NVIDIA driver 182.67 is buggy with Stage3D baseline mode",
       "cr_bugs": [172771],
       "os": {
         "type": "win"
@@ -523,7 +523,7 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "=",
-        "value": "8.17.11.8267"
+        "value": "182.67"
       },
       "features": [
         "flash_stage3d_baseline"
@@ -699,8 +699,8 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "between",
-        "value": "8.17.12.5729",
-        "value2": "8.17.12.8026"
+        "value": "257.29",
+        "value2": "280.26"
       },
       "features": [
         "accelerated_video_decode"
@@ -716,8 +716,8 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "between",
-        "value": "9.18.13.783",
-        "value2": "9.18.13.1090"
+        "value": "307.83",
+        "value2": "310.90"
       },
       "features": [
         "accelerated_video_decode"
@@ -1429,7 +1429,7 @@
       "vendor_id": "0x10de",
       "driver_version": {
         "op": "<=",
-        "value": "8.17.12.6973"
+        "value": "269.73"
       },
       "features": [
         "accelerated_webgl2"
diff --git a/gpu/ipc/common/gpu_info.mojom b/gpu/ipc/common/gpu_info.mojom
index 8d24a36..bf56d85 100644
--- a/gpu/ipc/common/gpu_info.mojom
+++ b/gpu/ipc/common/gpu_info.mojom
@@ -19,6 +19,7 @@
   string driver_vendor;
   string driver_version;
   string driver_date;
+  int32 cuda_compute_capability_major;
 };
 
 // gpu::VideoCodecProfile
diff --git a/gpu/ipc/common/gpu_info_struct_traits.cc b/gpu/ipc/common/gpu_info_struct_traits.cc
index 0696d192..cd6a8fe 100644
--- a/gpu/ipc/common/gpu_info_struct_traits.cc
+++ b/gpu/ipc/common/gpu_info_struct_traits.cc
@@ -16,6 +16,7 @@
   out->vendor_id = data.vendor_id();
   out->device_id = data.device_id();
   out->active = data.active();
+  out->cuda_compute_capability_major = data.cuda_compute_capability_major();
   return data.ReadVendorString(&out->vendor_string) &&
          data.ReadDeviceString(&out->device_string) &&
          data.ReadDriverVendor(&out->driver_vendor) &&
diff --git a/gpu/ipc/common/gpu_info_struct_traits.h b/gpu/ipc/common/gpu_info_struct_traits.h
index b5b9d6f3..2af4721 100644
--- a/gpu/ipc/common/gpu_info_struct_traits.h
+++ b/gpu/ipc/common/gpu_info_struct_traits.h
@@ -54,6 +54,11 @@
   static const std::string& driver_date(const gpu::GPUInfo::GPUDevice& input) {
     return input.driver_date;
   }
+
+  static int cuda_compute_capability_major(
+      const gpu::GPUInfo::GPUDevice& input) {
+    return input.cuda_compute_capability_major;
+  }
 };
 
 template <>
diff --git a/headless/lib/browser/headless_permission_manager.cc b/headless/lib/browser/headless_permission_manager.cc
index ce2b687..46fa0038 100644
--- a/headless/lib/browser/headless_permission_manager.cc
+++ b/headless/lib/browser/headless_permission_manager.cc
@@ -73,8 +73,8 @@
 
 int HeadlessPermissionManager::SubscribePermissionStatusChange(
     content::PermissionType permission,
+    content::RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
   return content::PermissionController::kNoPendingOperation;
 }
diff --git a/headless/lib/browser/headless_permission_manager.h b/headless/lib/browser/headless_permission_manager.h
index 86488a0a..95cadf7 100644
--- a/headless/lib/browser/headless_permission_manager.h
+++ b/headless/lib/browser/headless_permission_manager.h
@@ -49,8 +49,8 @@
       const GURL& requesting_origin) override;
   int SubscribePermissionStatusChange(
       content::PermissionType permission,
+      content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const GURL& embedding_origin,
       const base::Callback<void(blink::mojom::PermissionStatus)>& callback)
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index ff04033..1aa05022 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -1398,6 +1398,7 @@
 #pragma mark - Promo support
 
 - (void)scheduleShowPromo {
+  [self.mainBVC.dispatcher showConsentBumpIfNeeded];
   // Don't show promos if first run is shown.  (Note:  This flag is only YES
   // while the first run UI is visible.  However, as this function is called
   // immediately after the UI is shown, it's a safe check.)
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.h b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.h
index ee2f3e15..5feda6d2 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.h
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.h
@@ -64,6 +64,7 @@
     base::Time delete_end;
     BrowsingDataRemoveMask mask;
     base::OnceClosure callback;
+    base::Time task_started;
   };
 
   // Setter for |is_removing_|; DCHECKs that we can only start removing if we're
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
index 59b439f..6df5a4b 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -276,7 +276,8 @@
 void BrowsingDataRemoverImpl::RunNextTask() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!removal_queue_.empty());
-  const RemovalTask& removal_task = removal_queue_.front();
+  RemovalTask& removal_task = removal_queue_.front();
+  removal_task.task_started = base::Time::Now();
   RemoveImpl(removal_task.delete_begin, removal_task.delete_end,
              removal_task.mask);
 }
@@ -674,6 +675,22 @@
 
   {
     RemovalTask task = std::move(removal_queue_.front());
+    // Only log clear browsing data on regular browsing mode. In OTR mode, only
+    // few types of data are cleared and the rest is handled by deleting the
+    // browser state, so logging in these cases will render the histogram not
+    // useful.
+    if (!browser_state_->IsOffTheRecord()) {
+      base::TimeDelta delta = base::Time::Now() - task.task_started;
+      bool is_deletion_start_earliest = task.delete_begin.is_null();
+      bool is_deletion_end_now = task.delete_end.is_max();
+      if (is_deletion_start_earliest && is_deletion_end_now) {
+        UMA_HISTOGRAM_MEDIUM_TIMES(
+            "History.ClearBrowsingData.Duration.FullDeletion", delta);
+      } else {
+        UMA_HISTOGRAM_MEDIUM_TIMES(
+            "History.ClearBrowsingData.Duration.PartialDeletion", delta);
+      }
+    }
     removal_queue_.pop();
 
     // Schedule the task to be executed soon. This ensure that the IsRemoving()
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.mm
index 54e1eb99..577acd18 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.mm
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #import "base/test/ios/wait_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "components/open_from_clipboard/fake_clipboard_recent_content.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
@@ -26,6 +27,9 @@
 #error "This file requires ARC support."
 #endif
 
+using base::test::ios::WaitUntilConditionOrTimeout;
+using base::test::ios::kWaitForActionTimeout;
+
 namespace {
 
 // Flags passed when calling Remove(). Clear as much data as possible, avoiding
@@ -45,6 +49,11 @@
     BrowsingDataRemoveMask::REMOVE_VISITED_LINKS |
     BrowsingDataRemoveMask::REMOVE_LAST_USER_ACCOUNT;
 
+const char kFullDeletionHistogram[] =
+    "History.ClearBrowsingData.Duration.FullDeletion";
+const char kPartialDeletionHistogram[] =
+    "History.ClearBrowsingData.Duration.PartialDeletion";
+
 // Observer used to validate that BrowsingDataRemoverImpl notifies its
 // observers.
 class TestBrowsingDataRemoverObserver : public BrowsingDataRemoverObserver {
@@ -114,12 +123,11 @@
                                 kRemoveMask, base::DoNothing());
 
   TestBrowsingDataRemoverObserver* observer_ptr = &observer;
-  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForActionTimeout, ^{
-        // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
-        base::RunLoop().RunUntilIdle();
-        return observer_ptr->last_remove_mask() == kRemoveMask;
-      }));
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
+    // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
+    base::RunLoop().RunUntilIdle();
+    return observer_ptr->last_remove_mask() == kRemoveMask;
+  }));
 }
 
 // Tests that BrowsingDataRemoverImpl::Remove() can be called multiple times.
@@ -134,12 +142,55 @@
                                   --remaining_calls;
                                 }));
 
-  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForActionTimeout, ^{
-        // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
-        base::RunLoop().RunUntilIdle();
-        return remaining_calls == 0;
-      }));
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
+    // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
+    base::RunLoop().RunUntilIdle();
+    return remaining_calls == 0;
+  }));
+}
+
+// Tests that BrowsingDataRemoverImpl::Remove() Logs the duration to the correct
+// histogram for full deletion.
+TEST_F(BrowsingDataRemoverImplTest, LogDurationForFullDeletion) {
+  base::HistogramTester histogram_tester;
+  __block int remaining_calls = 1;
+  histogram_tester.ExpectTotalCount(kFullDeletionHistogram, 0);
+  histogram_tester.ExpectTotalCount(kPartialDeletionHistogram, 0);
+
+  browsing_data_remover_.Remove(browsing_data::TimePeriod::ALL_TIME,
+                                kRemoveMask, base::BindOnce(^{
+                                  --remaining_calls;
+                                }));
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
+    // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
+    base::RunLoop().RunUntilIdle();
+    return remaining_calls == 0;
+  }));
+
+  histogram_tester.ExpectTotalCount(kFullDeletionHistogram, 1);
+  histogram_tester.ExpectTotalCount(kPartialDeletionHistogram, 0);
+}
+
+// Tests that BrowsingDataRemoverImpl::Remove() Logs the duration to the correct
+// histogram for partial deletion.
+TEST_F(BrowsingDataRemoverImplTest, LogDurationForPartialDeletion) {
+  base::HistogramTester histogram_tester;
+  __block int remaining_calls = 1;
+  histogram_tester.ExpectTotalCount(kFullDeletionHistogram, 0);
+  histogram_tester.ExpectTotalCount(kPartialDeletionHistogram, 0);
+
+  browsing_data_remover_.Remove(browsing_data::TimePeriod::LAST_HOUR,
+                                kRemoveMask, base::BindOnce(^{
+                                  --remaining_calls;
+                                }));
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
+    // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
+    base::RunLoop().RunUntilIdle();
+    return remaining_calls == 0;
+  }));
+
+  histogram_tester.ExpectTotalCount(kFullDeletionHistogram, 0);
+  histogram_tester.ExpectTotalCount(kPartialDeletionHistogram, 1);
 }
 
 // Tests that BrowsingDataRemoverImpl::Remove() can finish performing its
@@ -154,10 +205,9 @@
   // Simulate destruction of BrowserState.
   browsing_data_remover_.Shutdown();
 
-  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForActionTimeout, ^{
-        // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
-        base::RunLoop().RunUntilIdle();
-        return remaining_calls == 0;
-      }));
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
+    // Spin the RunLoop as WaitUntilConditionOrTimeout doesn't.
+    base::RunLoop().RunUntilIdle();
+    return remaining_calls == 0;
+  }));
 }
diff --git a/ios/chrome/browser/infobars/infobar.mm b/ios/chrome/browser/infobars/infobar.mm
index f68bbe1..b363de4 100644
--- a/ios/chrome/browser/infobars/infobar.mm
+++ b/ios/chrome/browser/infobars/infobar.mm
@@ -31,6 +31,7 @@
 InfoBarIOS::~InfoBarIOS() {
   DCHECK(controller_);
   [controller_ detachView];
+  [controller_ setDelegate:nullptr];
   controller_ = nil;
 }
 
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
index 0c6556985..f3da9ae8 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -62,6 +62,7 @@
 #include "ios/chrome/browser/unified_consent/feature.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_thread.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -158,7 +159,7 @@
     metrics::MetricsLogUploader::MetricServiceType service_type,
     const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
   return std::make_unique<metrics::NetMetricsLogUploader>(
-      GetApplicationContext()->GetSystemURLRequestContext(), server_url,
+      GetApplicationContext()->GetSharedURLLoaderFactory(), server_url,
       insecure_server_url, mime_type, service_type, on_upload_complete);
 }
 
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index b14479bc1..e24dab4 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -345,6 +345,7 @@
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/app_launcher",
     "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/authentication/consent_bump",
     "//ios/chrome/browser/ui/autofill:autofill",
     "//ios/chrome/browser/ui/bookmarks",
     "//ios/chrome/browser/ui/browser_container",
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index b188d4b6..c5afa910 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -42,6 +42,7 @@
     "//components/signin/core/browser",
     "//components/signin/ios/browser",
     "//components/strings",
+    "//components/unified_consent",
     "//google_apis",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/authentication/authentication_constants.h b/ios/chrome/browser/ui/authentication/authentication_constants.h
index 11e2ce8..7b67c717 100644
--- a/ios/chrome/browser/ui/authentication/authentication_constants.h
+++ b/ios/chrome/browser/ui/authentication/authentication_constants.h
@@ -12,8 +12,8 @@
 extern const CGFloat kAuthenticationHeaderImageWidth;
 
 // Font sizes
-extern const CGFloat kAuthenticationTitleFontSize;
-extern const CGFloat kAuthenticationTextFontSize;
+extern const UIFontTextStyle kAuthenticationTitleFontStyle;
+extern const UIFontTextStyle kAuthenticationTextFontStyle;
 
 // Color displayed in the non-safe area.
 extern const int kAuthenticationHeaderBackgroundColor;
diff --git a/ios/chrome/browser/ui/authentication/authentication_constants.mm b/ios/chrome/browser/ui/authentication/authentication_constants.mm
index 3d7cace..8257d4c 100644
--- a/ios/chrome/browser/ui/authentication/authentication_constants.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_constants.mm
@@ -11,8 +11,8 @@
 const CGFloat kAuthenticationHeaderImageHeight = 88.;
 const CGFloat kAuthenticationHeaderImageWidth = 360.;
 
-const CGFloat kAuthenticationTitleFontSize = 23.;
-const CGFloat kAuthenticationTextFontSize = 12.;
+const UIFontTextStyle kAuthenticationTitleFontStyle = UIFontTextStyleTitle2;
+const UIFontTextStyle kAuthenticationTextFontStyle = UIFontTextStyleCaption1;
 
 const int kAuthenticationHeaderBackgroundColor = 0xf8f9fa;
 const CGFloat kAuthenticationHorizontalMargin = 16.;
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 3ac9fad..ab76c9a 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -22,6 +22,7 @@
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/unified_consent/unified_consent_service.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/signin/account_tracker_service_factory.h"
@@ -45,6 +46,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
 #include "ios/chrome/browser/unified_consent/feature.h"
+#include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h"
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -296,6 +298,14 @@
 
 - (void)acceptSignInAndCommitSyncChanges {
   DCHECK(_didSignIn);
+  if (_unifiedConsentEnabled) {
+    // The consent has to be given as soon as the user is signed in. Even when
+    // they open the settings through the link.
+    unified_consent::UnifiedConsentService* unifiedConsentService =
+        UnifiedConsentServiceFactory::GetForBrowserState(_browserState);
+    DCHECK(unifiedConsentService);
+    unifiedConsentService->SetUnifiedConsentGiven(true);
+  }
   SyncSetupServiceFactory::GetForBrowserState(_browserState)->CommitChanges();
   [self acceptSignInAndShowAccountsSettings:_unifiedConsentCoordinator
                                                 .settingsLinkWasTapped];
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn b/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
index ffa5eed..4d5a260 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
@@ -19,9 +19,11 @@
     ":consent_bump_ui",
     "//base",
     "//components/strings",
+    "//components/unified_consent",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/authentication/unified_consent",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
+    "//ios/chrome/browser/unified_consent",
     "//ui/base",
   ]
 }
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h
index 29d1aa2..9b7a49e 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h
@@ -7,6 +7,9 @@
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
 @protocol ConsentBumpCoordinatorDelegate;
 
 // Coordinator handling the consent bump.
@@ -18,6 +21,10 @@
 // Delegate for this coordinator.
 @property(nonatomic, weak) id<ConsentBumpCoordinatorDelegate> delegate;
 
+// Returns YES if the consent bump should be presented to the user.
++ (BOOL)shouldShowConsentBumpWithBrowserState:
+    (ios::ChromeBrowserState*)browserState;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_CONSENT_BUMP_CONSENT_BUMP_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
index 775a726..c34573a 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
@@ -5,12 +5,14 @@
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h"
 
 #include "base/logging.h"
+#include "components/unified_consent/unified_consent_service.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_mediator.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_personalization_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h"
+#include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -46,6 +48,13 @@
 @synthesize personalizationCoordinator = _personalizationCoordinator;
 @synthesize mediator = _mediator;
 
++ (BOOL)shouldShowConsentBumpWithBrowserState:
+    (ios::ChromeBrowserState*)browserState {
+  unified_consent::UnifiedConsentService* consent_service =
+      UnifiedConsentServiceFactory::GetForBrowserState(browserState);
+  return consent_service && consent_service->ShouldShowConsentBump();
+}
+
 #pragma mark - Properties
 
 - (UIViewController*)viewController {
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_personalization_view_controller.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_personalization_view_controller.mm
index 3a41b4a..1a33e27 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_personalization_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_personalization_view_controller.mm
@@ -86,7 +86,7 @@
       l10n_util::GetNSString(IDS_IOS_CONSENT_BUMP_PERSONALIZATION_TITLE);
   title.textColor =
       [UIColor colorWithWhite:0 alpha:kAuthenticationTitleColorAlpha];
-  title.font = [UIFont systemFontOfSize:kAuthenticationTitleFontSize];
+  title.font = [UIFont preferredFontForTextStyle:kAuthenticationTitleFontStyle];
   title.numberOfLines = 0;
   [container addSubview:title];
 
@@ -97,7 +97,7 @@
       l10n_util::GetNSString(IDS_IOS_CONSENT_BUMP_PERSONALIZATION_MESSAGE);
   text.textColor =
       [UIColor colorWithWhite:0 alpha:kAuthenticationTextColorAlpha];
-  text.font = [UIFont systemFontOfSize:kAuthenticationTextFontSize];
+  text.font = [UIFont preferredFontForTextStyle:kAuthenticationTextFontStyle];
   text.numberOfLines = 0;
   [container addSubview:text];
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm
index 9ef77112..a41ae4c 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm
@@ -31,7 +31,6 @@
 - (instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier {
   self = [super initWithReuseIdentifier:reuseIdentifier];
   if (self) {
-    self.contentView.backgroundColor = UIColor.whiteColor;
     UILabel* label = [[UILabel alloc] init];
     label.translatesAutoresizingMaskIntoConstraints = NO;
     label.text =
@@ -53,6 +52,10 @@
       @"V:|-(TopMargin)-[label]",
     ];
     ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
+
+    self.isAccessibilityElement = YES;
+    self.accessibilityLabel =
+        l10n_util::GetNSString(IDS_IOS_ACCOUNT_IDENTITY_CHOOSER_CHOOSE_ACCOUNT);
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
index f13ed8b..75ca9b0 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
@@ -116,6 +116,10 @@
     AddSameCenterYConstraint(self, _arrowDownImageView);
     AddSameCenterConstraints(_checkmarkImageView, _arrowDownImageView);
     ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
+
+    // Accessibility.
+    self.isAccessibilityElement = YES;
+    self.accessibilityTraits = UIAccessibilityTraitButton;
   }
   return self;
 }
@@ -127,6 +131,8 @@
   self.enabled = canChangeIdentity;
   self.arrowDownImageView.hidden = !canChangeIdentity;
   self.checkmarkImageView.hidden = canChangeIdentity;
+  self.accessibilityTraits = canChangeIdentity ? UIAccessibilityTraitButton
+                                               : UIAccessibilityTraitStaticText;
 }
 
 - (void)setIdentityAvatar:(UIImage*)identityAvatar {
@@ -137,8 +143,11 @@
   DCHECK(email);
   if (!name.length) {
     [self.identityView setTitle:email subtitle:nil];
+    self.accessibilityLabel = email;
   } else {
     [self.identityView setTitle:name subtitle:email];
+    self.accessibilityLabel =
+        [NSString stringWithFormat:@"%@, %@", name, email];
   }
 }
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
index c80fa97..4954719 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
@@ -193,7 +193,7 @@
   _consentStringIds.push_back(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE);
   title.textColor =
       [UIColor colorWithWhite:0 alpha:kAuthenticationTitleColorAlpha];
-  title.font = [UIFont systemFontOfSize:kAuthenticationTitleFontSize];
+  title.font = [UIFont preferredFontForTextStyle:kAuthenticationTitleFontStyle];
   title.numberOfLines = 0;
 
   [container addSubview:title];
@@ -374,7 +374,7 @@
   DCHECK(parentView);
   UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
   label.translatesAutoresizingMaskIntoConstraints = NO;
-  label.font = [UIFont systemFontOfSize:kAuthenticationTextFontSize];
+  label.font = [UIFont preferredFontForTextStyle:kAuthenticationTextFontStyle];
   label.text = l10n_util::GetNSString(stringId);
   _consentStringIds.push_back(stringId);
   label.textColor =
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index b5a3927..efa5474 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -117,6 +117,8 @@
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h"
 #import "ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.h"
+#import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.h"
+#import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h"
 #import "ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h"
 #import "ios/chrome/browser/ui/background_generator.h"
@@ -424,6 +426,7 @@
                                     AppRatingPromptDelegate,
                                     BubblePresenterDelegate,
                                     CaptivePortalDetectorTabHelperDelegate,
+                                    ConsentBumpCoordinatorDelegate,
                                     CRWNativeContentProvider,
                                     CRWWebStateDelegate,
                                     DialogPresenterDelegate,
@@ -737,6 +740,9 @@
 // Whether the safe area insets should be used to adjust the viewport.
 @property(nonatomic, readonly) BOOL usesSafeInsetsForViewportAdjustments;
 
+// Coordinator to ask the user for the new consent.
+@property(nonatomic, strong) ConsentBumpCoordinator* consentBumpCoordinator;
+
 // BVC initialization
 // ------------------
 // If the BVC is initialized with a valid browser state & tab model immediately,
@@ -944,6 +950,7 @@
 // DialogPresenterDelegate property
 @synthesize dialogPresenterDelegateIsPresenting =
     _dialogPresenterDelegateIsPresenting;
+@synthesize consentBumpCoordinator = _consentBumpCoordinator;
 
 #pragma mark - Object lifecycle
 
@@ -5046,6 +5053,21 @@
   }
 }
 
+- (void)showConsentBumpIfNeeded {
+  DCHECK(!self.consentBumpCoordinator);
+  if (![ConsentBumpCoordinator
+          shouldShowConsentBumpWithBrowserState:_browserState]) {
+    return;
+  }
+  self.consentBumpCoordinator =
+      [[ConsentBumpCoordinator alloc] initWithBaseViewController:self];
+  self.consentBumpCoordinator.delegate = self;
+  [self.consentBumpCoordinator start];
+  [self presentViewController:self.consentBumpCoordinator.viewController
+                     animated:YES
+                   completion:nil];
+}
+
 #pragma mark - ToolbarOwner (Public)
 
 - (CGRect)toolbarFrame {
@@ -5972,4 +5994,20 @@
   [self.dispatcher showSignin:command baseViewController:self];
 }
 
+#pragma mark - ConsentBumpCoordinatorDelegate
+
+- (void)consentBumpCoordinator:(ConsentBumpCoordinator*)coordinator
+    didFinishNeedingToShowSettings:(BOOL)shouldShowSettings {
+  DCHECK(self.consentBumpCoordinator);
+  DCHECK(self.consentBumpCoordinator.viewController);
+  [self.consentBumpCoordinator.viewController
+      dismissViewControllerAnimated:YES
+                         completion:nil];
+  self.consentBumpCoordinator = nil;
+  if (shouldShowSettings) {
+    // TODO(crbug.com/827072): Needs to open the sync and Google services
+    // panel from the settings.
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 944ec99..8deedff2 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -119,6 +119,9 @@
 // Prepares the browser to display a popup menu.
 - (void)prepareForPopupMenuPresentation:(PopupMenuCommandType)type;
 
+// Shows the consent bump if it is required.
+- (void)showConsentBumpIfNeeded;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.h b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.h
index 61f0ff4..f445df7 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ios/web/public/web_state/web_state_observer.h"
+#include "url/gurl.h"
 
 class FullscreenController;
 class FullscreenMediator;
@@ -52,6 +53,8 @@
   std::unique_ptr<ScopedFullscreenDisabler> ssl_disabler_;
   // The disabler for loading.
   std::unique_ptr<ScopedFullscreenDisabler> loading_disabler_;
+  // The URL received in the NavigationContext of the last finished navigation.
+  GURL last_navigation_url_;
 };
 
 #endif  // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_WEB_STATE_OBSERVER_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
index 1ce7a5d..a67c76f 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -13,6 +13,7 @@
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/ssl_status.h"
+#include "ios/web/public/url_util.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
@@ -81,6 +82,10 @@
 void FullscreenWebStateObserver::DidFinishNavigation(
     web::WebState* web_state,
     web::NavigationContext* navigation_context) {
+  const GURL& navigation_url = navigation_context->GetUrl();
+  bool url_changed = web::GURLByRemovingRefFromGURL(navigation_url) !=
+                     web::GURLByRemovingRefFromGURL(last_navigation_url_);
+  last_navigation_url_ = navigation_url;
   // Due to limitations in WKWebView's rendering, different MIME types must be
   // inset using different techniques:
   // - PDFs need to be inset using the scroll view's |contentInset| property or
@@ -94,9 +99,9 @@
   web_state->GetWebViewProxy().shouldUseViewContentInset =
       force_content_inset ||
       web_state->GetContentsMimeType() == "application/pdf";
-  // Reset the model so that the toolbar is visible when navigating to a new
-  // document.
-  if (!navigation_context->IsSameDocument())
+  // Only reset the model for document-changing navigations or same-document
+  // navigations that update the visible URL.
+  if (!navigation_context->IsSameDocument() || url_changed)
     model_->ResetForNavigation();
   // Disable fullscreen if there is a problem with the SSL status.
   SetDisableFullscreenForSSL(ShouldDisableFullscreenForWebStateSSL(web_state));
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
index 062211df..35a21caf 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer_unittest.mm
@@ -71,19 +71,60 @@
   EXPECT_EQ(model().progress(), 1.0);
 }
 
-// Tests that the FullscreenModel is not reset for a same-document navigation.
-TEST_F(FullscreenWebStateObserverTest, NoResetForSameDocument) {
+// Tests that the FullscreenModel is not reset for same-document navigations
+// with the same URL.
+TEST_F(FullscreenWebStateObserverTest, NoResetForSameDocumentSameURL) {
+  // Navigate to a URL.
+  web::FakeNavigationContext context;
+  context.SetUrl(GURL("https://www.test.com"));
+  web_state().OnNavigationFinished(&context);
+  model().SetYContentOffset(0.0);
   // Simulate a scroll to 0.5 progress.
   SimulateFullscreenUserScrollForProgress(&model(), 0.5);
   EXPECT_EQ(model().progress(), 0.5);
-  // Simulate a same-document navigation and verify that the 0.5 progress hasn't
-  // been reset to 1.0.
-  web::FakeNavigationContext context;
+  // Simulate a same-document navigation to the same URL and verify that the 0.5
+  // progress hasn't been reset to 1.0.
   context.SetIsSameDocument(true);
   web_state().OnNavigationFinished(&context);
   EXPECT_EQ(model().progress(), 0.5);
 }
 
+// Tests that the FullscreenModel is not reset for a same-document navigation.
+TEST_F(FullscreenWebStateObserverTest, NoResetForSameDocumentFragmentChange) {
+  // Navigate to a URL.
+  web::FakeNavigationContext context;
+  context.SetUrl(GURL("https://www.test.com"));
+  web_state().OnNavigationFinished(&context);
+  model().SetYContentOffset(0.0);
+  // Simulate a scroll to 0.5 progress.
+  SimulateFullscreenUserScrollForProgress(&model(), 0.5);
+  EXPECT_EQ(model().progress(), 0.5);
+  // Simulate a same-document navigation to a URL with a different fragment and
+  // verify that the 0.5 progress hasn't been reset to 1.0.
+  context.SetUrl(GURL("https://www.test.com#fragment"));
+  context.SetIsSameDocument(true);
+  web_state().OnNavigationFinished(&context);
+  EXPECT_EQ(model().progress(), 0.5);
+}
+
+// Tests that the FullscreenModel is not reset for a same-document navigation.
+TEST_F(FullscreenWebStateObserverTest, ResetForSameDocumentURLChange) {
+  // Navigate to a URL.
+  web::FakeNavigationContext context;
+  context.SetUrl(GURL("https://www.test.com"));
+  web_state().OnNavigationFinished(&context);
+  model().SetYContentOffset(0.0);
+  // Simulate a scroll to 0.5 progress.
+  SimulateFullscreenUserScrollForProgress(&model(), 0.5);
+  EXPECT_EQ(model().progress(), 0.5);
+  // Simulate a same-document navigation to a new URL and verify that the 0.5
+  // progress is reset to 1.0.
+  context.SetUrl(GURL("https://www.test2.com"));
+  context.SetIsSameDocument(true);
+  web_state().OnNavigationFinished(&context);
+  EXPECT_EQ(model().progress(), 1.0);
+}
+
 // Tests that the model is disabled when a load is occurring.
 TEST_F(FullscreenWebStateObserverTest, DisableDuringLoadWithUIRefreshDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 377e54e..3939e7b8 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -42,13 +42,13 @@
     "dataplan_usage_collection_view_controller.mm",
     "do_not_track_collection_view_controller.h",
     "do_not_track_collection_view_controller.mm",
-    "google_services_settings_command_handler.h",
     "google_services_settings_consumer.h",
     "google_services_settings_coordinator.h",
     "google_services_settings_coordinator.mm",
     "google_services_settings_local_commands.h",
     "google_services_settings_mediator.h",
     "google_services_settings_mediator.mm",
+    "google_services_settings_service_delegate.h",
     "google_services_settings_view_controller.h",
     "google_services_settings_view_controller.mm",
     "google_services_settings_view_controller_model_delegate.h",
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
index d3f107c..287a2b5 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
@@ -16,6 +16,7 @@
 #import "ios/chrome/browser/ui/settings/google_services_settings_local_commands.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
+#include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -39,26 +40,29 @@
 
 - (void)start {
   UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
-  GoogleServicesSettingsViewController* controller =
+  GoogleServicesSettingsViewController* viewController =
       [[GoogleServicesSettingsViewController alloc]
           initWithLayout:layout
                    style:CollectionViewControllerStyleAppBar];
-  controller.presentationDelegate = self;
-  controller.localDispatcher = self;
-  self.viewController = controller;
+  viewController.presentationDelegate = self;
+  viewController.localDispatcher = self;
+  self.viewController = viewController;
   SyncSetupService* syncSetupService =
       SyncSetupServiceFactory::GetForBrowserState(self.browserState);
   browser_sync::ProfileSyncService* syncService =
       ProfileSyncServiceFactory::GetForBrowserState(self.browserState);
+  unified_consent::UnifiedConsentService* unifiedConsentService =
+      UnifiedConsentServiceFactory::GetForBrowserState(self.browserState);
   self.mediator = [[GoogleServicesSettingsMediator alloc]
-      initWithPrefService:self.browserState->GetPrefs()
-              syncService:syncService
-         syncSetupService:syncSetupService];
-  self.mediator.consumer = controller;
+        initWithPrefService:self.browserState->GetPrefs()
+                syncService:syncService
+           syncSetupService:syncSetupService
+      unifiedConsentService:unifiedConsentService];
+  self.mediator.consumer = viewController;
   self.mediator.authService =
       AuthenticationServiceFactory::GetForBrowserState(self.browserState);
-  controller.modelDelegate = self.mediator;
-  controller.commandHandler = self.mediator;
+  viewController.modelDelegate = self.mediator;
+  viewController.serviceDelegate = self.mediator;
   DCHECK(self.navigationController);
   [self.navigationController pushViewController:self.viewController
                                        animated:YES];
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
index cfd671dd..b043652 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
@@ -98,7 +98,8 @@
     EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
   [SigninEarlGreyUI signinWithIdentity:[SigninEarlGreyUtils fakeIdentity1]];
   PrefService* prefService = GetOriginalBrowserState()->GetPrefs();
-  prefService->SetBoolean(kUnifiedConsentGiven, true);
+  GREYAssert(prefService->GetBoolean(kUnifiedConsentGiven),
+             @"Unified consent should be given");
   [self openGoogleServicesSettings];
   [self assertSyncEverythingSection];
   [self assertPersonalizedServicesCollapsed:YES];
@@ -205,13 +206,18 @@
         [NSString stringWithFormat:@"%@, %@", accessibilityLabel,
                                    GetNSString(detailTextID)];
   }
-  return [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityLabel(accessibilityLabel),
-                                   grey_kindOfClass(
-                                       [UICollectionViewCell class]),
-                                   grey_sufficientlyVisible(), nil)]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 150)
+  id<GREYMatcher> cellMatcher =
+      grey_allOf(grey_accessibilityLabel(accessibilityLabel),
+                 grey_kindOfClass([UICollectionViewCell class]),
+                 grey_sufficientlyVisible(), nil);
+  // Needs to scroll slowly to make sure to not miss a cell if it is not
+  // currently on the screen. It should not be bigger than the visible part
+  // of the collection view.
+  const CGFloat kPixelsToScroll = 300;
+  id<GREYAction> searchAction =
+      grey_scrollInDirection(kGREYDirectionDown, kPixelsToScroll);
+  return [[EarlGrey selectElementWithMatcher:cellMatcher]
+         usingSearchAction:searchAction
       onElementWithMatcher:self.scrollViewMatcher];
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
index 1703b34..7f0955b 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
@@ -7,8 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/settings/google_services_settings_command_handler.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_consumer.h"
+#import "ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller_model_delegate.h"
 
@@ -20,10 +20,13 @@
 namespace browser_sync {
 class ProfileSyncService;
 };
+namespace unified_consent {
+class UnifiedConsentService;
+}  // namespace unified_consent
 
 // Mediator for the Google services settings.
 @interface GoogleServicesSettingsMediator
-    : NSObject<GoogleServicesSettingsCommandHandler,
+    : NSObject<GoogleServicesSettingsServiceDelegate,
                GoogleServicesSettingsViewControllerModelDelegate>
 
 // View controller.
@@ -37,6 +40,8 @@
                         syncService:
                             (browser_sync::ProfileSyncService*)syncService
                    syncSetupService:(SyncSetupService*)syncSetupService
+              unifiedConsentService:
+                  (unified_consent::UnifiedConsentService*)unifiedConsentService
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
index 8c876f6..af64b70 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
@@ -11,6 +11,7 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/unified_consent/pref_names.h"
+#include "components/unified_consent/unified_consent_service.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/sync/sync_observer_bridge.h"
@@ -84,6 +85,9 @@
   std::unique_ptr<SyncObserverBridge> _syncObserver;
 }
 
+// Unified consent service.
+@property(nonatomic, assign)
+    unified_consent::UnifiedConsentService* unifiedConsentService;
 // Returns YES if the user is authenticated.
 @property(nonatomic, assign, readonly) BOOL isAuthenticated;
 // Returns YES if the user has given his consent to use Google services.
@@ -116,6 +120,7 @@
 
 @implementation GoogleServicesSettingsMediator
 
+@synthesize unifiedConsentService = _unifiedConsentService;
 @synthesize consumer = _consumer;
 @synthesize authService = _authService;
 @synthesize prefService = _prefService;
@@ -132,17 +137,21 @@
 
 #pragma mark - Load model
 
-- (instancetype)initWithPrefService:(PrefService*)prefService
-                        syncService:
-                            (browser_sync::ProfileSyncService*)syncService
-                   syncSetupService:(SyncSetupService*)syncSetupService {
+- (instancetype)
+  initWithPrefService:(PrefService*)prefService
+          syncService:(browser_sync::ProfileSyncService*)syncService
+     syncSetupService:(SyncSetupService*)syncSetupService
+unifiedConsentService:
+    (unified_consent::UnifiedConsentService*)unifiedConsentService {
   self = [super init];
   if (self) {
     DCHECK(prefService);
     DCHECK(syncService);
     DCHECK(syncSetupService);
+    DCHECK(unifiedConsentService);
     _prefService = prefService;
     _syncSetupService = syncSetupService;
+    _unifiedConsentService = unifiedConsentService;
     _syncObserver.reset(new SyncObserverBridge(self, syncService));
     prefObserverBridge_ = std::make_unique<PrefObserverBridge>(self);
     prefChangeRegistrar_.Init(prefService);
@@ -207,7 +216,7 @@
 }
 
 - (BOOL)isConsentGiven {
-  return self.prefService->GetBoolean(kUnifiedConsentGiven);
+  return self.unifiedConsentService->IsUnifiedConsentGiven();
 }
 
 - (CollectionViewItem*)syncEverythingItem {
@@ -496,14 +505,14 @@
   [self loadNonPersonalizedSection];
 }
 
-#pragma mark - GoogleServicesSettingsCommandHandler
+#pragma mark - GoogleServicesSettingsServiceDelegate
 
 - (void)toggleSyncEverythingWithValue:(BOOL)value {
   if (value == self.isConsentGiven)
     return;
   // Mark the switch has being animated to avoid being reloaded.
   base::AutoReset<BOOL> autoReset(&_syncEverythingSwitchBeingAnimated, YES);
-  self.prefService->SetBoolean(kUnifiedConsentGiven, value);
+  self.unifiedConsentService->SetUnifiedConsentGiven(value);
 }
 
 - (void)toggleSyncDataSync:(NSInteger)dataTypeInt withValue:(BOOL)value {
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h b/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
similarity index 95%
rename from ios/chrome/browser/ui/settings/google_services_settings_command_handler.h
rename to ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
index f3a0032f..fb7bcd16 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_COMMAND_HANDLER_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_COMMAND_HANDLER_H_
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_SERVICE_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_SERVICE_DELEGATE_H_
 
 // List of Google Services Settings commands.
 typedef NS_ENUM(NSInteger, GoogleServicesSettingsCommandID) {
@@ -34,7 +34,7 @@
 };
 
 // Protocol to handle Google services settings commands.
-@protocol GoogleServicesSettingsCommandHandler<NSObject>
+@protocol GoogleServicesSettingsServiceDelegate<NSObject>
 
 // Called when GoogleServicesSettingsCommandIDToggleSyncEverything is triggered.
 - (void)toggleSyncEverythingWithValue:(BOOL)value;
@@ -60,4 +60,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_COMMAND_HANDLER_H_
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_SERVICE_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
index 22b1f69..27b0026 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
@@ -10,7 +10,7 @@
 #import "ios/chrome/browser/ui/settings/google_services_settings_consumer.h"
 
 @class GoogleServicesSettingsViewController;
-@protocol GoogleServicesSettingsCommandHandler;
+@protocol GoogleServicesSettingsServiceDelegate;
 @protocol GoogleServicesSettingsLocalCommands;
 @protocol GoogleServicesSettingsViewControllerModelDelegate;
 
@@ -36,8 +36,8 @@
 @property(nonatomic, weak) id<GoogleServicesSettingsViewControllerModelDelegate>
     modelDelegate;
 // Handler for GoogleServicesSettingsCommand.
-@property(nonatomic, weak) id<GoogleServicesSettingsCommandHandler>
-    commandHandler;
+@property(nonatomic, weak) id<GoogleServicesSettingsServiceDelegate>
+    serviceDelegate;
 // Local command dispatcher.
 @property(nonatomic, weak) id<GoogleServicesSettingsLocalCommands>
     localDispatcher;
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
index b386b175..cef94c6 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
@@ -10,8 +10,8 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_collapsible_item.h"
 #import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
-#import "ios/chrome/browser/ui/settings/google_services_settings_command_handler.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_local_commands.h"
+#import "ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller_model_delegate.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -32,7 +32,7 @@
 
 @synthesize presentationDelegate = _presentationDelegate;
 @synthesize modelDelegate = _modelDelegate;
-@synthesize commandHandler = _commandHandler;
+@synthesize serviceDelegate = _serviceDelegate;
 @synthesize localDispatcher = _localDispatcher;
 
 - (instancetype)initWithLayout:(UICollectionViewLayout*)layout
@@ -104,23 +104,23 @@
       static_cast<GoogleServicesSettingsCommandID>(syncSwitchItem.commandID);
   switch (commandID) {
     case GoogleServicesSettingsCommandIDToggleSyncEverything:
-      [self.commandHandler toggleSyncEverythingWithValue:isOn];
+      [self.serviceDelegate toggleSyncEverythingWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleDataTypeSync:
-      [self.commandHandler toggleSyncDataSync:syncSwitchItem.dataType
-                                    withValue:isOn];
+      [self.serviceDelegate toggleSyncDataSync:syncSwitchItem.dataType
+                                     withValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService:
-      [self.commandHandler toggleAutocompleteSearchesServiceWithValue:isOn];
+      [self.serviceDelegate toggleAutocompleteSearchesServiceWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDTogglePreloadPagesService:
-      [self.commandHandler togglePreloadPagesServiceWithValue:isOn];
+      [self.serviceDelegate togglePreloadPagesServiceWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleImproveChromeService:
-      [self.commandHandler toggleImproveChromeServiceWithValue:isOn];
+      [self.serviceDelegate toggleImproveChromeServiceWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleBetterSearchAndBrowsingService:
-      [self.commandHandler toggleBetterSearchAndBrowsingServiceWithValue:isOn];
+      [self.serviceDelegate toggleBetterSearchAndBrowsingServiceWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDNoOp:
     case GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog:
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
index 50820db..36ca586 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -634,6 +634,7 @@
   CollectionViewItem* item =
       [self.collectionViewModel itemAtIndexPath:indexPath];
   switch (item.type) {
+    case ItemTypeSite:
     case ItemTypeUsername:
     case ItemTypePassword:
       return [MDCCollectionViewCell
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 583fe530..4222789 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1652,6 +1652,19 @@
               BindToCurrentLoop(base::BindRepeating(
                   &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
       bridge_->SetContentsOpaque(opaque_);
+
+      // If the element is already in Picture-in-Picture mode, it means that it
+      // was set in this mode prior to this load, with a different
+      // WebMediaPlayerImpl. The new player needs to send its id, size and
+      // surface id to the browser process to make sure the states are properly
+      // updated.
+      // TODO(872056): the surface should be activated but for some reasons, it
+      // does not. It is possible that this will no longer be neded after 872056
+      // is fixed.
+      if (client_->DisplayType() ==
+          WebMediaPlayer::DisplayType::kPictureInPicture) {
+        OnSurfaceIdUpdated(bridge_->GetSurfaceId());
+      }
     }
   }
 
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index ace97d8..74e74d8a 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -755,6 +755,16 @@
   // the codec isn't already draining.
   drain_type_ = drain_type;
 
+  // We can safely invalidate outstanding buffers for both types of drain, and
+  // doing so can only make the drain complete quicker.  Note that we do this
+  // even if we're eliding the drain, since we're either going to flush the
+  // codec or destroy it.  While we're not required to do this, it might affect
+  // stability if we don't (https://crbug.com/869365).  AVDA, in particular,
+  // dropped all pending codec output buffers when starting a reset (seek) or
+  // a destroy.
+  if (codec_)
+    codec_->DiscardOutputBuffers();
+
   // Skip the drain if possible. Only VP8 codecs need draining because
   // they can hang in release() or flush() otherwise
   // (http://crbug.com/598963).
@@ -770,9 +780,6 @@
   if (!codec_->IsDraining())
     pending_decodes_.push_back(PendingDecode::CreateEos());
 
-  // We can safely invalidate outstanding buffers for both types of drain, and
-  // doing so can only make the drain complete quicker.
-  codec_->DiscardOutputBuffers();
   PumpCodec(true);
 }
 
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index 5e6c3808..aeb5026 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -127,7 +127,12 @@
     : receiver_(receiver) {
 }
 
-ControlMessageProxy::~ControlMessageProxy() = default;
+ControlMessageProxy::~ControlMessageProxy() {
+  // If this is destroyed in the middle of a flush, make sure the callback is
+  // still run.
+  if (!pending_flush_callback_.is_null())
+    RunFlushForTestingClosure();
+}
 
 void ControlMessageProxy::QueryVersion(
     const base::Callback<void(uint32_t)>& callback) {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 52af8ae..be36d39 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -5259,7 +5259,7 @@
     data += [
       "tools/testserver/",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
       "$root_out_dir/pyproto/google/",
     ]
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc
index 6a4ce587..67bd849 100644
--- a/net/base/network_change_notifier_fuchsia_unittest.cc
+++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -152,6 +152,11 @@
                            fuchsia::netstack::NetAddress addr,
                            uint8_t prefixLen,
                            SetInterfaceAddressCallback callback) override {}
+  void RemoveInterfaceAddress(
+      uint32_t nicid,
+      fuchsia::netstack::NetAddress addr,
+      uint8_t prefixLen,
+      RemoveInterfaceAddressCallback callback) override {}
   void SetDhcpClientStatus(uint32_t nicid,
                            bool enabled,
                            SetDhcpClientStatusCallback callback) override {}
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 9bcf4c3..afd1792 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -65,7 +65,8 @@
       "static_spki_hashes": [
         "GoogleBackup2048",
         "GoogleG2",
-        "GeoTrustGlobal",
+        "GoogleG3",
+        "GTSCA1O1",
         "GlobalSignRootCA_R2"
       ],
       "report_uri": "http://clients3.google.com/cert_upload_json"
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 23216f0..8415ee28 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -109,6 +109,61 @@
 wSHGFg==
 -----END CERTIFICATE-----
 
+GoogleG3
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw
+HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
+U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
+MTUwMDAwNDJaMFQxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
+U2VydmljZXMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKUkvqHv/OJGuo2nIYaNVW
+XQ5IWi01CXZaz6TIHLGp/lOJ+600/4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK
+71G4nzKMfHCGUksW/mona+Y2emJQ2N+aicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9
+RUk2T0HNouB2VzxoMXlkyW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1z
+ouAqYGVQMc/7sy+/EYhALrVJEA8KbtyX+r8snwU5C1hUrwaW6MWOARa8qBpNQcWT
+kaIeoYvy/sGIJEmjR0vFEwHdp1cSaWIr6/4g72n7OqXwfinu7ZYW97EfoOSQJeAz
+AgMBAAGjggEzMIIBLzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH
+AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCa
+Z3Z2sS3ChtCDoH6mfrpLMB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYu
+MDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdv
+b2cvZ3NyMjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dz
+cjIvZ3NyMi5jcmwwPwYDVR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYc
+aHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA
+HLeJluRT7bvs26gyAZ8so81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2e
+ux9LSD+PAj2LIYRFHW31/6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt+nlPq
+wnb8Oa2I/maSJukcxDjNSfpDh/Bd1lZNgdd/8cLdsE3+wypufJ9uXO1iQpnh9zbu
+FIwsIONGl1p3A8CgxkqI/UAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy
+7a8IVk6wuy6pm+T7HT4LY8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZV
+c7o835DLAFshEWfC7TIe3g==
+-----END CERTIFICATE-----
+
+GTSCA1O1
+-----BEGIN CERTIFICATE-----
+MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw
+HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
+U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
+MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
+U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv
+UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr
+mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac
+xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK
+FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X
+rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV
+HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud
+EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G
+A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl
+BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp
+MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g
+BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y
+ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H
+TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN
+FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz
+mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW
+IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ
+USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg==
+-----END CERTIFICATE-----
+
 GeoTrustGlobal
 -----BEGIN CERTIFICATE-----
 MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
diff --git a/net/proxy_resolution/proxy_config_service_android.cc b/net/proxy_resolution/proxy_config_service_android.cc
index cbc0a904..8c5ee731 100644
--- a/net/proxy_resolution/proxy_config_service_android.cc
+++ b/net/proxy_resolution/proxy_config_service_android.cc
@@ -211,7 +211,8 @@
         network_task_runner_(network_task_runner),
         jni_task_runner_(jni_task_runner),
         get_property_callback_(get_property_callback),
-        exclude_pac_url_(false) {
+        exclude_pac_url_(false),
+        has_proxy_override_(false) {
   }
 
   void SetupJNI() {
@@ -265,6 +266,9 @@
   // Called in the JNI sequence.
   void ProxySettingsChanged() {
     DCHECK(InJNISequence());
+    if (has_proxy_override_)
+      return;
+
     ProxyConfigWithAnnotation proxy_config;
     GetLatestProxyConfigInternal(get_property_callback_, &proxy_config);
     network_task_runner_->PostTask(
@@ -278,6 +282,9 @@
                               const std::string& pac_url,
                               const std::vector<std::string>& exclusion_list) {
     DCHECK(InJNISequence());
+    if (has_proxy_override_)
+      return;
+
     ProxyConfigWithAnnotation proxy_config;
     if (exclude_pac_url_) {
       CreateStaticProxyConfig(host, port, "", exclusion_list, &proxy_config);
@@ -294,6 +301,33 @@
     exclude_pac_url_ = enabled;
   }
 
+  // Called in the JNI sequence.
+  void SetProxyOverride(const std::string& host,
+                        int port,
+                        const std::vector<std::string>& exclusion_list) {
+    DCHECK(InJNISequence());
+    has_proxy_override_ = true;
+    ProxyConfigWithAnnotation proxy_config;
+    CreateStaticProxyConfig(host, port, "", exclusion_list, &proxy_config);
+    network_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&Delegate::SetNewConfigInNetworkSequence, this,
+                              proxy_config));
+  }
+
+  // Called in the JNI sequence.
+  void ClearProxyOverride() {
+    DCHECK(InJNISequence());
+    if (!has_proxy_override_)
+      return;
+
+    ProxyConfigWithAnnotation proxy_config;
+    GetLatestProxyConfigInternal(get_property_callback_, &proxy_config);
+    network_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&Delegate::SetNewConfigInNetworkSequence, this,
+                              proxy_config));
+    has_proxy_override_ = false;
+  }
+
  private:
   friend class base::RefCountedThreadSafe<Delegate>;
 
@@ -365,6 +399,8 @@
   GetPropertyCallback get_property_callback_;
   ProxyConfigWithAnnotation proxy_config_;
   bool exclude_pac_url_;
+  // This may only be accessed or modified on the JNI thread
+  bool has_proxy_override_;
 
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
@@ -414,4 +450,15 @@
   delegate_->ProxySettingsChanged();
 }
 
+void ProxyConfigServiceAndroid::SetProxyOverride(
+    const std::string& host,
+    int port,
+    const std::vector<std::string>& exclusion_list) {
+  delegate_->SetProxyOverride(host, port, exclusion_list);
+}
+
+void ProxyConfigServiceAndroid::ClearProxyOverride() {
+  delegate_->ClearProxyOverride();
+}
+
 } // namespace net
diff --git a/net/proxy_resolution/proxy_config_service_android.h b/net/proxy_resolution/proxy_config_service_android.h
index fd2729d..ed70a5df 100644
--- a/net/proxy_resolution/proxy_config_service_android.h
+++ b/net/proxy_resolution/proxy_config_service_android.h
@@ -76,6 +76,11 @@
   ConfigAvailability GetLatestProxyConfig(
       ProxyConfigWithAnnotation* config) override;
 
+  void SetProxyOverride(const std::string& host,
+                        int port,
+                        const std::vector<std::string>& exclusion_list);
+  void ClearProxyOverride();
+
  private:
   friend class ProxyConfigServiceAndroidTestBase;
   class Delegate;
diff --git a/net/proxy_resolution/proxy_config_service_android_unittest.cc b/net/proxy_resolution/proxy_config_service_android_unittest.cc
index 859019a..8c89180 100644
--- a/net/proxy_resolution/proxy_config_service_android_unittest.cc
+++ b/net/proxy_resolution/proxy_config_service_android_unittest.cc
@@ -110,6 +110,18 @@
     EXPECT_EQ(expected, proxy_info.ToPacString());
   }
 
+  void SetProxyOverride(const std::string& host,
+                        int port,
+                        const std::vector<std::string>& exclusion_list) {
+    service_.SetProxyOverride(host, port, exclusion_list);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void ClearProxyOverride() {
+    service_.ClearProxyOverride();
+    base::RunLoop().RunUntilIdle();
+  }
+
   StringMap configuration_;
   TestObserver observer_;
   // |java_looper_preparer_| appears before |service_| so that Java's Looper is
@@ -166,6 +178,124 @@
   TestMapping("http://example.com/", "PROXY httpproxy.com:80");
 }
 
+TEST_F(ProxyConfigServiceAndroidTest, TestOverrideNoProxy) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the default proxy
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the custom proxy
+  SetProxyOverride("httpoverrideproxy.com", 200, exclusion_list);
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview uses the default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "DIRECT");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestOverrideAndProxy) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the default proxy
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the custom proxy
+  SetProxyOverride("httpoverrideproxy.com", 200, exclusion_list);
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview continues to use the custom proxy
+  AddProperty("http.proxyHost", "httpsomeproxy.com");
+  ProxySettingsChanged();
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview uses the non default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestProxyAndOverride) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the default proxy
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the non default proxy
+  AddProperty("http.proxyHost", "httpsomeproxy.com");
+  ProxySettingsChanged();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+
+  // Check that webview uses the custom proxy
+  SetProxyOverride("httpoverrideproxy.com", 200, exclusion_list);
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview uses the non default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestOverrideThenProxy) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the default proxy
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the custom proxy
+  SetProxyOverride("httpoverrideproxy.com", 200, exclusion_list);
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview uses the default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the non default proxy
+  AddProperty("http.proxyHost", "httpsomeproxy.com");
+  ProxySettingsChanged();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestClearOverride) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the default proxy
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview uses the default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "DIRECT");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestProxyAndClearOverride) {
+  std::vector<std::string> exclusion_list;
+
+  // Check that webview uses the non default proxy
+  AddProperty("http.proxyHost", "httpsomeproxy.com");
+  ProxySettingsChanged();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+
+  // Check that webview uses the non default proxy
+  ClearProxyOverride();
+  TestMapping("http://example.com/", "PROXY httpsomeproxy.com:80");
+}
+
+TEST_F(ProxyConfigServiceAndroidTest, TestOverrideExclusionList) {
+  std::vector<std::string> exclusion_list;
+  exclusion_list.push_back("excluded.com");
+
+  // Check that webview uses the default proxy
+  TestMapping("http://excluded.com/", "DIRECT");
+  TestMapping("http://example.com/", "DIRECT");
+
+  // Check that webview handles the exclusion list correctly
+  SetProxyOverride("httpoverrideproxy.com", 200, exclusion_list);
+  TestMapping("http://excluded.com/", "DIRECT");
+  TestMapping("http://example.com/", "PROXY httpoverrideproxy.com:200");
+
+  // Check that webview uses the default proxy
+  ClearProxyOverride();
+  TestMapping("http://excluded.com/", "DIRECT");
+  TestMapping("http://example.com/", "DIRECT");
+}
+
 // !! The following test cases are automatically generated from
 // !! net/android/tools/proxy_test_cases.py.
 // !! Please edit that file instead of editing the test cases below and
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index cdaae400..d0740c6 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -1743,6 +1743,7 @@
 }
 
 void QuicChromiumClientSession::OnNoNewNetwork() {
+  DCHECK(IsCryptoHandshakeConfirmed());
   wait_for_new_network_ = true;
 
   DVLOG(1) << "Force blocking the packet writer";
@@ -2090,6 +2091,13 @@
 
   LogHandshakeStatusOnConnectionMigrationSignal();
 
+  if (!IsCryptoHandshakeConfirmed()) {
+    HistogramAndLogMigrationFailure(
+        net_log_, MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
+        connection_id(), "Path degrading before handshake confirmed");
+    return;
+  }
+
   const NetLogWithSource migration_net_log = NetLogWithSource::Make(
       net_log_.net_log(), NetLogSourceType::QUIC_CONNECTION_MIGRATION);
   migration_net_log.BeginEvent(
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index da6418f..6068944 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -109,6 +109,7 @@
   MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED,
   MIGRATION_STATUS_TIMEOUT,
   MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED,
+  MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
   MIGRATION_STATUS_MAX
 };
 
diff --git a/net/quic/quic_stream_factory_peer.cc b/net/quic/quic_stream_factory_peer.cc
index b7dca56d..efbb473 100644
--- a/net/quic/quic_stream_factory_peer.cc
+++ b/net/quic/quic_stream_factory_peer.cc
@@ -49,6 +49,19 @@
   return factory->HasActiveCertVerifierJob(server_id);
 }
 
+// static
+QuicChromiumClientSession* QuicStreamFactoryPeer::GetPendingSession(
+    QuicStreamFactory* factory,
+    const quic::QuicServerId& server_id,
+    const HostPortPair& destination) {
+  QuicSessionKey session_key(server_id, SocketTag());
+  QuicStreamFactory::QuicSessionAliasKey key(destination, session_key);
+  DCHECK(factory->HasActiveJob(session_key));
+  DCHECK_EQ(factory->all_sessions_.size(), 1u);
+  DCHECK(key == factory->all_sessions_.begin()->second);
+  return factory->all_sessions_.begin()->first;
+}
+
 QuicChromiumClientSession* QuicStreamFactoryPeer::GetActiveSession(
     QuicStreamFactory* factory,
     const quic::QuicServerId& server_id) {
diff --git a/net/quic/quic_stream_factory_peer.h b/net/quic/quic_stream_factory_peer.h
index 008a298..cebf703 100644
--- a/net/quic/quic_stream_factory_peer.h
+++ b/net/quic/quic_stream_factory_peer.h
@@ -47,6 +47,11 @@
   static bool HasActiveCertVerifierJob(QuicStreamFactory* factory,
                                        const quic::QuicServerId& server_id);
 
+  static QuicChromiumClientSession* GetPendingSession(
+      QuicStreamFactory* factory,
+      const quic::QuicServerId& server_id,
+      const HostPortPair& destination);
+
   static QuicChromiumClientSession* GetActiveSession(
       QuicStreamFactory* factory,
       const quic::QuicServerId& server_id);
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 33fc61e..218afb4d 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -333,6 +333,15 @@
                                                            server_id);
   }
 
+  // Get the pending, not activated session, if there is only one session alive.
+  QuicChromiumClientSession* GetPendingSession(
+      const HostPortPair& host_port_pair) {
+    quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(),
+                                 false);
+    return QuicStreamFactoryPeer::GetPendingSession(factory_.get(), server_id,
+                                                    host_port_pair);
+  }
+
   QuicChromiumClientSession* GetActiveSession(
       const HostPortPair& host_port_pair) {
     quic::QuicServerId server_id(host_port_pair.host(), host_port_pair.port(),
@@ -4382,6 +4391,54 @@
   EXPECT_TRUE(quic_data3.AllWriteDataConsumed());
 }
 
+// This test verifies that the connection will not attempt connection migration
+// (send connectivity probes on alternate path) when path degrading is detected
+// and handshake is not confirmed.
+TEST_P(QuicStreamFactoryTest,
+       NoMigrationOnPathDegradingBeforeHandshakeConfirmed) {
+  InitializeConnectionMigrationV2Test(
+      {kDefaultNetworkForTests, kNewNetworkForTests});
+
+  // Using a testing task runner.
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get());
+
+  // Use cold start mode to send crypto message for handshake.
+  crypto_client_stream_factory_.set_handshake_mode(
+      MockCryptoClientStream::COLD_START_WITH_CHLO_SENT);
+
+  MockQuicData socket_data;
+  socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+  socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1));
+  socket_data.AddSocketDataToFactory(socket_factory_.get());
+
+  // Create request and QuicHttpStream.
+  QuicStreamRequest request(factory_.get());
+  EXPECT_EQ(ERR_IO_PENDING,
+            request.Request(host_port_pair_, version_, privacy_mode_,
+                            DEFAULT_PRIORITY, SocketTag(),
+                            /*cert_verify_flags=*/0, url_, net_log_,
+                            &net_error_details_, callback_.callback()));
+
+  base::RunLoop().RunUntilIdle();
+
+  // Ensure that session is alive but not active.
+  EXPECT_FALSE(HasActiveSession(host_port_pair_));
+  EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_));
+  QuicChromiumClientSession* session = GetPendingSession(host_port_pair_);
+  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+  EXPECT_EQ(0u, task_runner->GetPendingTaskCount());
+
+  // Cause the connection to report path degrading to the session.
+  // Session will ignore the signal as handshake is not completed.
+  session->connection()->OnPathDegradingTimeout();
+  EXPECT_EQ(0u, task_runner->GetPendingTaskCount());
+
+  EXPECT_FALSE(HasActiveSession(host_port_pair_));
+  EXPECT_TRUE(socket_data.AllReadDataConsumed());
+  EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
 // Test that connection will be closed with PACKET_WRITE_ERROR if a write error
 // is triggered before handshake is confirmed and connection migration is turned
 // on.
diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc
index 3ae8f73..4daaf91 100644
--- a/printing/pdf_metafile_skia.cc
+++ b/printing/pdf_metafile_skia.cc
@@ -218,10 +218,14 @@
   DCHECK_EQ(data_->type_, SkiaDocumentType::MSKP);
   DCHECK(!data_->pdf_data_);
 
-  SkDynamicMemoryWStream stream;
+  cc::PlaybackParams::CustomDataRasterCallback custom_callback =
+      base::BindRepeating(&PdfMetafileSkia::CustomDataToSkPictureCallback,
+                          base::Unretained(this));
   sk_sp<SkPicture> pic = ToSkPicture(data_->pages_[0].content_,
-                                     SkRect::MakeSize(data_->pages_[0].size_));
+                                     SkRect::MakeSize(data_->pages_[0].size_),
+                                     nullptr, custom_callback);
   SkSerialProcs procs = SerializationProcs(&data_->subframe_content_info_);
+  SkDynamicMemoryWStream stream;
   pic->serialize(&stream, &procs);
   data_->pdf_data_ = stream.detachAsStream();
 }
diff --git a/remoting/client/audio/BUILD.gn b/remoting/client/audio/BUILD.gn
index 63571057..dda19b5 100644
--- a/remoting/client/audio/BUILD.gn
+++ b/remoting/client/audio/BUILD.gn
@@ -10,6 +10,7 @@
     "audio_frame_supplier.h",
     "audio_jitter_buffer.cc",
     "audio_jitter_buffer.h",
+    "audio_playback_sink.h",
     "audio_player.cc",
     "audio_player.h",
     "audio_player_android.cc",
@@ -18,6 +19,8 @@
     "audio_player_buffer.h",
     "audio_stream_consumer.cc",
     "audio_stream_consumer.h",
+    "audio_stream_format.cc",
+    "audio_stream_format.h",
   ]
 
   configs += [ "//remoting/build/config:version" ]
@@ -37,6 +40,14 @@
   }
 }
 
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "fake_async_audio_data_supplier.cc",
+    "fake_async_audio_data_supplier.h",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
 
diff --git a/remoting/client/audio/async_audio_data_supplier.h b/remoting/client/audio/async_audio_data_supplier.h
index eed0b7d..c3c91a2 100644
--- a/remoting/client/audio/async_audio_data_supplier.h
+++ b/remoting/client/audio/async_audio_data_supplier.h
@@ -12,7 +12,8 @@
 // This interface allows caller to asynchronously request for audio data.
 class AsyncAudioDataSupplier {
  public:
-  struct GetDataRequest {
+  class GetDataRequest {
+   public:
     // |data| must outlive |this|.
     GetDataRequest(void* data, size_t bytes_needed);
     virtual ~GetDataRequest();
diff --git a/remoting/client/audio/audio_jitter_buffer.cc b/remoting/client/audio/audio_jitter_buffer.cc
index c7fe0cd..80c074b 100644
--- a/remoting/client/audio/audio_jitter_buffer.cc
+++ b/remoting/client/audio/audio_jitter_buffer.cc
@@ -36,17 +36,6 @@
 
 namespace remoting {
 
-bool AudioJitterBuffer::StreamFormat::operator==(
-    const StreamFormat& other) const {
-  return bytes_per_sample == other.bytes_per_sample &&
-         channels == other.channels && sample_rate == other.sample_rate;
-}
-
-bool AudioJitterBuffer::StreamFormat::operator!=(
-    const StreamFormat& other) const {
-  return !(*this == other);
-}
-
 AudioJitterBuffer::AudioJitterBuffer(
     OnFormatChangedCallback on_format_changed) {
   DETACH_FROM_THREAD(thread_checker_);
@@ -61,7 +50,7 @@
   DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding());
   DCHECK_NE(AudioPacket::SAMPLING_RATE_INVALID, packet->sampling_rate());
 
-  StreamFormat stream_format;
+  AudioStreamFormat stream_format;
   stream_format.bytes_per_sample = packet->bytes_per_sample();
   stream_format.channels = packet->channels();
   stream_format.sample_rate = packet->sampling_rate();
@@ -103,13 +92,13 @@
   queued_requests_.clear();
 }
 
-void AudioJitterBuffer::ResetBuffer(const StreamFormat& new_format) {
+void AudioJitterBuffer::ResetBuffer(const AudioStreamFormat& new_format) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   queued_packets_.clear();
   queued_bytes_ = 0;
   first_packet_offset_ = 0;
   ClearGetDataRequests();
-  stream_format_ = std::make_unique<StreamFormat>(new_format);
+  stream_format_ = std::make_unique<AudioStreamFormat>(new_format);
   underrun_protection_mode_ = true;
   if (on_format_changed_) {
     on_format_changed_.Run(*stream_format_);
diff --git a/remoting/client/audio/audio_jitter_buffer.h b/remoting/client/audio/audio_jitter_buffer.h
index 2fbf0966..5f744f5b 100644
--- a/remoting/client/audio/audio_jitter_buffer.h
+++ b/remoting/client/audio/audio_jitter_buffer.h
@@ -14,6 +14,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "remoting/client/audio/async_audio_data_supplier.h"
+#include "remoting/client/audio/audio_stream_format.h"
 #include "remoting/proto/audio.pb.h"
 
 namespace remoting {
@@ -22,17 +23,8 @@
 // and feeds the requests with the data when the buffer has enough data.
 class AudioJitterBuffer : public AsyncAudioDataSupplier {
  public:
-  struct StreamFormat {
-    bool operator==(const StreamFormat& other) const;
-    bool operator!=(const StreamFormat& other) const;
-
-    int bytes_per_sample = 0;
-    int channels = 0;
-    int sample_rate = 0;
-  };
-
   using OnFormatChangedCallback =
-      base::RepeatingCallback<void(const StreamFormat& format)>;
+      base::RepeatingCallback<void(const AudioStreamFormat& format)>;
 
   // |callback| is called once the jitter buffer gets the first packet or the
   // stream format has been changed.
@@ -52,7 +44,7 @@
 
   // Clears the jitter buffer, drops all pending requests, and notify
   // |on_format_changed_| that the format has been changed.
-  void ResetBuffer(const StreamFormat& new_format);
+  void ResetBuffer(const AudioStreamFormat& new_format);
 
   // Feeds data from the jitter buffer into the pending requests. OnDataFilled()
   // will be called and request will be removed from the queue when a request
@@ -69,7 +61,7 @@
 
   // The stream format of the last audio packet. This is nullptr if the buffer
   // has never received any packet.
-  std::unique_ptr<StreamFormat> stream_format_;
+  std::unique_ptr<AudioStreamFormat> stream_format_;
 
   // AudioPackets queued up by the jitter buffer before they are consumed by
   // GetDataRequests.
diff --git a/remoting/client/audio/audio_jitter_buffer_unittest.cc b/remoting/client/audio/audio_jitter_buffer_unittest.cc
index 25a9ed46..d5d3e63 100644
--- a/remoting/client/audio/audio_jitter_buffer_unittest.cc
+++ b/remoting/client/audio/audio_jitter_buffer_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "remoting/client/audio/audio_jitter_buffer.h"
+#include "remoting/client/audio/audio_stream_format.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace remoting {
@@ -77,15 +78,15 @@
   std::list<std::unique_ptr<uint8_t[]>> consumer_buffers_;
 
  private:
-  struct SimpleGetDataRequest;
+  class SimpleGetDataRequest;
 
-  void OnFormatChanged(const AudioJitterBuffer::StreamFormat& format);
+  void OnFormatChanged(const AudioStreamFormat& format);
 
   AudioPacket::SamplingRate sample_rate_;
-  std::unique_ptr<AudioJitterBuffer::StreamFormat> stream_format_;
+  std::unique_ptr<AudioStreamFormat> stream_format_;
 };
 
-struct AudioJitterBufferTest::SimpleGetDataRequest
+class AudioJitterBufferTest::SimpleGetDataRequest
     : public AsyncAudioDataSupplier::GetDataRequest {
  public:
   SimpleGetDataRequest(AudioJitterBufferTest* test, size_t bytes_to_write);
@@ -164,9 +165,8 @@
 size_t AudioJitterBufferTest::GetNumQueuedRequests() const {
   return audio_->queued_requests_.size();
 }
-void AudioJitterBufferTest::OnFormatChanged(
-    const AudioJitterBuffer::StreamFormat& format) {
-  stream_format_ = std::make_unique<AudioJitterBuffer::StreamFormat>(format);
+void AudioJitterBufferTest::OnFormatChanged(const AudioStreamFormat& format) {
+  stream_format_ = std::make_unique<AudioStreamFormat>(format);
 }
 
 // SimpleGetDataRequest definitions
diff --git a/remoting/client/audio/audio_playback_sink.h b/remoting/client/audio/audio_playback_sink.h
new file mode 100644
index 0000000..a02615f
--- /dev/null
+++ b/remoting/client/audio/audio_playback_sink.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_CLIENT_AUDIO_AUDIO_PLAYBACK_SINK_H_
+#define REMOTING_CLIENT_AUDIO_AUDIO_PLAYBACK_SINK_H_
+
+#include "base/macros.h"
+
+namespace remoting {
+
+class AsyncAudioDataSupplier;
+struct AudioStreamFormat;
+
+// This is an interface acting as the downstream of AsyncAudioDataSupplier.
+class AudioPlaybackSink {
+ public:
+  AudioPlaybackSink() = default;
+  virtual ~AudioPlaybackSink() = default;
+
+  // Sets the data supplier to be used by the sink to request for more audio
+  // data.
+  // |supplier| must outlive |this|.
+  virtual void SetDataSupplier(AsyncAudioDataSupplier* supplier) = 0;
+
+  // Called whenever the stream format is first received or has been changed.
+  virtual void ResetStreamFormat(const AudioStreamFormat& format) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AudioPlaybackSink);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_AUDIO_AUDIO_PLAYBACK_SINK_H_
diff --git a/remoting/client/audio/audio_stream_format.cc b/remoting/client/audio/audio_stream_format.cc
new file mode 100644
index 0000000..3618615
--- /dev/null
+++ b/remoting/client/audio/audio_stream_format.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/client/audio/audio_stream_format.h"
+
+namespace remoting {
+
+bool AudioStreamFormat::operator==(const AudioStreamFormat& other) const {
+  return bytes_per_sample == other.bytes_per_sample &&
+         channels == other.channels && sample_rate == other.sample_rate;
+}
+
+bool AudioStreamFormat::operator!=(const AudioStreamFormat& other) const {
+  return !(*this == other);
+}
+
+}  // namespace remoting
diff --git a/remoting/client/audio/audio_stream_format.h b/remoting/client/audio/audio_stream_format.h
new file mode 100644
index 0000000..5e23978
--- /dev/null
+++ b/remoting/client/audio/audio_stream_format.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_CLIENT_AUDIO_AUDIO_STREAM_FORMAT_H_
+#define REMOTING_CLIENT_AUDIO_AUDIO_STREAM_FORMAT_H_
+
+namespace remoting {
+
+struct AudioStreamFormat {
+  bool operator==(const AudioStreamFormat& other) const;
+  bool operator!=(const AudioStreamFormat& other) const;
+
+  int bytes_per_sample = 0;
+  int channels = 0;
+  int sample_rate = 0;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_AUDIO_AUDIO_STREAM_FORMAT_H_
diff --git a/remoting/client/audio/fake_async_audio_data_supplier.cc b/remoting/client/audio/fake_async_audio_data_supplier.cc
new file mode 100644
index 0000000..072873f
--- /dev/null
+++ b/remoting/client/audio/fake_async_audio_data_supplier.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/client/audio/fake_async_audio_data_supplier.h"
+
+#include <utility>
+
+#include "base/logging.h"
+
+namespace remoting {
+
+FakeAsyncAudioDataSupplier::FakeAsyncAudioDataSupplier() = default;
+
+FakeAsyncAudioDataSupplier::~FakeAsyncAudioDataSupplier() = default;
+
+void FakeAsyncAudioDataSupplier::AsyncGetData(
+    std::unique_ptr<GetDataRequest> request) {
+  pending_requests_.push_back(std::move(request));
+
+  if (fulfill_requests_immediately_) {
+    FulfillAllRequests();
+  }
+}
+
+void FakeAsyncAudioDataSupplier::ClearGetDataRequests() {
+  pending_requests_.clear();
+}
+
+void FakeAsyncAudioDataSupplier::FulfillNextRequest() {
+  DCHECK_GT(pending_requests_count(), 0u);
+  auto& request = pending_requests_.front();
+  memset(request->data, kDummyAudioData, request->bytes_needed);
+  request->OnDataFilled();
+  pending_requests_.pop_front();
+  fulfilled_requests_count_++;
+}
+
+void FakeAsyncAudioDataSupplier::FulfillAllRequests() {
+  while (pending_requests_count() > 0) {
+    FulfillNextRequest();
+  }
+}
+
+void FakeAsyncAudioDataSupplier::ResetFulfilledRequestsCounter() {
+  fulfilled_requests_count_ = 0u;
+}
+
+}  // namespace remoting
diff --git a/remoting/client/audio/fake_async_audio_data_supplier.h b/remoting/client/audio/fake_async_audio_data_supplier.h
new file mode 100644
index 0000000..223b41bb
--- /dev/null
+++ b/remoting/client/audio/fake_async_audio_data_supplier.h
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_CLIENT_AUDIO_FAKE_ASYNC_AUDIO_DATA_SUPPLIER_H_
+#define REMOTING_CLIENT_AUDIO_FAKE_ASYNC_AUDIO_DATA_SUPPLIER_H_
+
+#include <cstdint>
+#include <list>
+#include <memory>
+
+#include "base/macros.h"
+#include "remoting/client/audio/async_audio_data_supplier.h"
+
+namespace remoting {
+
+// A fake AsyncAudioDataSupplier implementation for testing.
+class FakeAsyncAudioDataSupplier : public AsyncAudioDataSupplier {
+ public:
+  // Dummy audio data that will be filled into pending requests.
+  const uint8_t kDummyAudioData = 0x8b;
+
+  FakeAsyncAudioDataSupplier();
+  ~FakeAsyncAudioDataSupplier() override;
+
+  // AsyncAudioDataSupplier implementations.
+  void AsyncGetData(std::unique_ptr<GetDataRequest> request) override;
+  void ClearGetDataRequests() override;
+
+  // Fulfills the next pending request by filling it with |kDummyAudioData|.
+  void FulfillNextRequest();
+
+  // Fulfills all pending requests.
+  void FulfillAllRequests();
+
+  // Resets fulfilled_requests_count() to 0.
+  void ResetFulfilledRequestsCounter();
+
+  // Returns number of requests that are not fulfilled.
+  size_t pending_requests_count() const { return pending_requests_.size(); }
+
+  // Returns number of requests that have been fulfilled. Can be reset to 0 by
+  // calling ResetFulfilledRequestsCounter().
+  size_t fulfilled_requests_count() const { return fulfilled_requests_count_; }
+
+  // If this is true, the instance will immediately fulfill get-data requests
+  // when AsyncGetData is called, otherwise the caller needs to call
+  // FulfillNextRequest() or FulfillAllRequests() to fulfill the requests.
+  // The default value is false.
+  void set_fulfill_requests_immediately(bool fulfill_requests_immediately) {
+    fulfill_requests_immediately_ = fulfill_requests_immediately;
+  }
+
+ private:
+  bool fulfill_requests_immediately_ = false;
+  std::list<std::unique_ptr<GetDataRequest>> pending_requests_;
+  size_t fulfilled_requests_count_ = 0u;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeAsyncAudioDataSupplier);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_AUDIO_FAKE_ASYNC_AUDIO_DATA_SUPPLIER_H_
diff --git a/remoting/ios/BUILD.gn b/remoting/ios/BUILD.gn
index d99e335e..0d8fc28 100644
--- a/remoting/ios/BUILD.gn
+++ b/remoting/ios/BUILD.gn
@@ -78,7 +78,8 @@
   deps = [
     "//base/test:run_all_unittests",
     "//base/test:test_support",
-    "//remoting//ios/facade:unit_tests",
+    "//remoting/ios/audio:unit_tests",
+    "//remoting/ios/facade:unit_tests",
     "//remoting/ios/persistence:unit_tests",
   ]
 
diff --git a/remoting/ios/audio/BUILD.gn b/remoting/ios/audio/BUILD.gn
index 8132362..4bd0dd9 100644
--- a/remoting/ios/audio/BUILD.gn
+++ b/remoting/ios/audio/BUILD.gn
@@ -8,6 +8,8 @@
 
 source_set("audio") {
   sources = [
+    "audio_playback_sink_ios.cc",
+    "audio_playback_sink_ios.h",
     "audio_player_ios.h",
     "audio_player_ios.mm",
     "audio_player_ios_wrapper.h",
@@ -21,5 +23,26 @@
     "//remoting/client/audio",
   ]
 
+  public_deps = [
+    "//remoting/proto",
+  ]
+
+  libs = [ "AudioToolbox.framework" ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "audio_playback_sink_ios_unittest.cc",
+  ]
+  deps = [
+    ":audio",
+    "//remoting/client/audio:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
   configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/remoting/ios/audio/audio_playback_sink_ios.cc b/remoting/ios/audio/audio_playback_sink_ios.cc
new file mode 100644
index 0000000..3f0a908
--- /dev/null
+++ b/remoting/ios/audio/audio_playback_sink_ios.cc
@@ -0,0 +1,229 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/ios/audio/audio_playback_sink_ios.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "remoting/client/audio/async_audio_data_supplier.h"
+#include "remoting/client/audio/audio_stream_format.h"
+
+namespace remoting {
+
+namespace {
+
+// Once we receive the stream format, we create
+// |kRequiredBufferCountForPlayback| buffers from the audio queue, each with a
+// duration of |kBufferLength|. The buffers will then be transferred to the
+// supplier for priming. Once a buffer is filled up, we put it back to the audio
+// queue and start running the queue. Buffer that has been consumed by the audio
+// queue will be transferred back to the supplier for priming new audio data. We
+// stop running the audio queue once all buffers have been transferred to the
+// supplier.
+
+constexpr base::TimeDelta kBufferLength = base::TimeDelta::FromMilliseconds(10);
+constexpr int kRequiredBufferCountForPlayback = 5;
+
+class AudioQueueGetDataRequest : public AsyncAudioDataSupplier::GetDataRequest {
+ public:
+  AudioQueueGetDataRequest(
+      AudioQueueBufferRef buffer,
+      base::OnceCallback<void(AudioQueueBufferRef)> on_data_received);
+  ~AudioQueueGetDataRequest() override;
+
+  void OnDataFilled() override;
+
+ private:
+  AudioQueueBufferRef buffer_;
+  base::OnceCallback<void(AudioQueueBufferRef)> on_data_received_;
+};
+
+AudioQueueGetDataRequest::AudioQueueGetDataRequest(
+    AudioQueueBufferRef buffer,
+    base::OnceCallback<void(AudioQueueBufferRef)> on_data_received)
+    : GetDataRequest(buffer->mAudioData, buffer->mAudioDataBytesCapacity),
+      buffer_(buffer),
+      on_data_received_(std::move(on_data_received)) {
+  buffer_->mAudioDataByteSize = buffer_->mAudioDataBytesCapacity;
+}
+
+// Note that disposing of the output queue also disposes all of its buffers,
+// so no cleanup is needed here.
+AudioQueueGetDataRequest::~AudioQueueGetDataRequest() = default;
+
+void AudioQueueGetDataRequest::OnDataFilled() {
+  std::move(on_data_received_).Run(buffer_);
+}
+
+}  // namespace
+
+AudioPlaybackSinkIos::AudioPlaybackSinkIos() : weak_factory_(this) {
+  DETACH_FROM_THREAD(thread_checker_);
+}
+
+AudioPlaybackSinkIos::~AudioPlaybackSinkIos() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DisposeOutputQueue();
+}
+
+void AudioPlaybackSinkIos::SetDataSupplier(AsyncAudioDataSupplier* supplier) {
+  DCHECK(supplier);
+  supplier_ = supplier;
+}
+
+void AudioPlaybackSinkIos::ResetStreamFormat(const AudioStreamFormat& format) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  stream_format_.mSampleRate = format.sample_rate;
+  stream_format_.mFormatID = kAudioFormatLinearPCM;
+  stream_format_.mFormatFlags =
+      kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
+  stream_format_.mBitsPerChannel = 8 * format.bytes_per_sample;
+  stream_format_.mChannelsPerFrame = format.channels;
+  stream_format_.mBytesPerPacket = format.bytes_per_sample * format.channels;
+  stream_format_.mBytesPerFrame = stream_format_.mBytesPerPacket;
+  stream_format_.mFramesPerPacket = 1;
+  stream_format_.mReserved = 0;
+
+  ResetOutputQueue();
+}
+
+void AudioPlaybackSinkIos::AsyncGetAudioData(AudioQueueBufferRef buffer) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(supplier_);
+
+  priming_buffers_count_++;
+
+  supplier_->AsyncGetData(std::make_unique<AudioQueueGetDataRequest>(
+      buffer, base::BindOnce(&AudioPlaybackSinkIos::OnAudioDataReceived,
+                             weak_factory_.GetWeakPtr())));
+
+  if (state_ == State::RUNNING &&
+      priming_buffers_count_ == kRequiredBufferCountForPlayback) {
+    // Buffer underrun. Stop playback immediately.
+    StopPlayback();
+    return;
+  }
+}
+
+void AudioPlaybackSinkIos::OnAudioDataReceived(AudioQueueBufferRef buffer) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  AudioQueueEnqueueBuffer(output_queue_, buffer, 0, nullptr);
+  priming_buffers_count_--;
+
+  if (state_ == State::STOPPED) {
+    StartPlayback();
+  }
+}
+
+// static
+void AudioPlaybackSinkIos::OnBufferDequeued(void* context,
+                                            AudioQueueRef outAQ,
+                                            AudioQueueBufferRef buffer) {
+  AudioPlaybackSinkIos* instance =
+      reinterpret_cast<AudioPlaybackSinkIos*>(context);
+  DCHECK(instance);
+  instance->AsyncGetAudioData(buffer);
+}
+
+void AudioPlaybackSinkIos::StartPlayback() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (state_ != State::STOPPED) {
+    return;
+  }
+  DCHECK(output_queue_);
+  OSStatus err = AudioQueueStart(output_queue_, nullptr);
+
+  if (err) {
+    // This could be a transient failure when we try to start playback while the
+    // app is resuming from the background. We can reset the queue for now and
+    // wait for new audio data to trigger StartPlayback() again.
+    LOG(ERROR) << "AudioQueueStart failed: " << err;
+
+    // StartPlayback() may be called from inside GetDataRequest::OnDataFilled().
+    // In this case ResetOutputQueue() must be called in a separate task because
+    // it alters the pending requests in |supplier_|.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&AudioPlaybackSinkIos::ResetOutputQueue,
+                                  weak_factory_.GetWeakPtr()));
+    state_ = State::SCHEDULED_TO_RESET;
+  } else {
+    state_ = State::RUNNING;
+  }
+}
+
+void AudioPlaybackSinkIos::StopPlayback() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(output_queue_);
+
+  if (state_ != State::RUNNING) {
+    return;
+  }
+
+  // Note that AudioQueueStop() will immediately return all enqueued buffers to
+  // us, which calls AsyncGetAudioData(). We change the state to STOPPED before
+  // AudioQueueStop() so that the buffers are immediately transferred to the
+  // supplier.
+  state_ = State::STOPPED;
+
+  OSStatus err = AudioQueueStop(output_queue_, /* Immediate */ true);
+  HandleError(err, "AudioQueueStop");
+}
+
+void AudioPlaybackSinkIos::ResetOutputQueue() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DisposeOutputQueue();
+
+  OSStatus err = AudioQueueNewOutput(&stream_format_, OnBufferDequeued, this,
+                                     CFRunLoopGetCurrent(),
+                                     kCFRunLoopCommonModes, 0, &output_queue_);
+  if (HandleError(err, "AudioQueueNewOutput")) {
+    return;
+  }
+
+  // Create buffers.
+  size_t buffer_byte_size = stream_format_.mSampleRate *
+                            stream_format_.mBytesPerPacket *
+                            kBufferLength.InSecondsF();
+  for (int i = 0; i < kRequiredBufferCountForPlayback; i++) {
+    AudioQueueBufferRef buffer;
+    OSStatus err =
+        AudioQueueAllocateBuffer(output_queue_, buffer_byte_size, &buffer);
+    if (HandleError(err, "AudioQueueAllocateBuffer")) {
+      return;
+    }
+
+    // Immediately request for audio data.
+    AsyncGetAudioData(buffer);
+  }
+}
+
+void AudioPlaybackSinkIos::DisposeOutputQueue() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(supplier_);
+  if (!output_queue_) {
+    return;
+  }
+
+  AudioQueueDispose(output_queue_, /* Immediate */ true);
+  supplier_->ClearGetDataRequests();
+  priming_buffers_count_ = 0;
+  output_queue_ = nullptr;
+
+  state_ = State::STOPPED;
+}
+
+bool AudioPlaybackSinkIos::HandleError(OSStatus err,
+                                       const char* function_name) {
+  if (err) {
+    LOG(DFATAL) << "Failed to call " << function_name
+                << ", error code: " << err;
+    DisposeOutputQueue();
+    return true;
+  }
+  return false;
+}
+
+}  // namespace remoting
diff --git a/remoting/ios/audio/audio_playback_sink_ios.h b/remoting/ios/audio/audio_playback_sink_ios.h
new file mode 100644
index 0000000..c125461
--- /dev/null
+++ b/remoting/ios/audio/audio_playback_sink_ios.h
@@ -0,0 +1,103 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_
+#define REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_
+
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "remoting/client/audio/audio_playback_sink.h"
+
+namespace remoting {
+
+// This is the iOS AudioPlaybackSink implementation that uses AudioQueue for
+// playback.
+class AudioPlaybackSinkIos : public AudioPlaybackSink {
+ public:
+  AudioPlaybackSinkIos();
+  ~AudioPlaybackSinkIos() override;
+
+  // AudioPlaybackSink implementations.
+  void SetDataSupplier(AsyncAudioDataSupplier* supplier) override;
+  void ResetStreamFormat(const AudioStreamFormat& format) override;
+
+ private:
+  // STOPPED <-----------------------------+------------+
+  //    | Received packet                  |            |
+  // (Start playback)--------+             |            |
+  //    | Failed             | Succeeded   | Buffer     |
+  //    v                    v             | Underrun   |
+  // SCHEDULED_TO_RESET    RUNNING---------+            |
+  //    |                    |                          |
+  //    |                    | Sink destructing or      | Audio queue
+  //    |                    | format resetting         | destroyed
+  //    +--------------------+--------------------------+
+  enum class State {
+    STOPPED,
+    SCHEDULED_TO_RESET,
+    RUNNING,
+  };
+
+  // Asks |supplier_| to fill audio data into the given buffer.
+  void AsyncGetAudioData(AudioQueueBufferRef buffer);
+
+  // Callback called when |supplier_| has finished filling data for |buffer|.
+  void OnAudioDataReceived(AudioQueueBufferRef buffer);
+
+  // Callback called when the AudioQueue API finished consuming the audio data.
+  static void OnBufferDequeued(void* context,
+                               AudioQueueRef outAQ,
+                               AudioQueueBufferRef buffer);
+
+  // Starts playback immediately. Posts task to reset the output queue if it
+  // fails to start.
+  void StartPlayback();
+
+  // Stops playback immediately.
+  void StopPlayback();
+
+  // Disposes the current output queue and its buffers, creates a new queue
+  // and buffers, and immediately request for audio data from |supplier_|.
+  void ResetOutputQueue();
+
+  // Disposes the current output queue and its buffers.
+  void DisposeOutputQueue();
+
+  // If |err| is not no-error, prints an error log at DFATAL level and disposes
+  // the current output queue. The sink will then not be running until
+  // ResetStreamFormat() is called again.
+  // Returns true if error occurs and the output queue has been disposed.
+  bool HandleError(OSStatus err, const char* function_name);
+
+  THREAD_CHECKER(thread_checker_);
+
+  AsyncAudioDataSupplier* supplier_ = nullptr;
+
+  // Number of buffers that are currently transferred to |supplier_| for
+  // priming.
+  size_t priming_buffers_count_ = 0;
+
+  // The current stream format.
+  AudioStreamBasicDescription stream_format_;
+
+  // The output queue. nullptr if ResetStreamFormat() has not been called.
+  AudioQueueRef output_queue_ = nullptr;
+
+  // The current state.
+  State state_ = State::STOPPED;
+
+  base::WeakPtrFactory<AudioPlaybackSinkIos> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioPlaybackSinkIos);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_IOS_AUDIO_AUDIO_PLAYBACK_SINK_IOS_H_
diff --git a/remoting/ios/audio/audio_playback_sink_ios_unittest.cc b/remoting/ios/audio/audio_playback_sink_ios_unittest.cc
new file mode 100644
index 0000000..268d7f6
--- /dev/null
+++ b/remoting/ios/audio/audio_playback_sink_ios_unittest.cc
@@ -0,0 +1,218 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/ios/audio/audio_playback_sink_ios.h"
+
+#include "base/bind.h"
+#include "base/test/bind_test_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "remoting/client/audio/audio_stream_format.h"
+#include "remoting/client/audio/fake_async_audio_data_supplier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+namespace {
+
+constexpr AudioStreamFormat kStreamFormat = {2, 2, 44100};
+constexpr base::TimeDelta kBufferPlaybackTimeout =
+    base::TimeDelta::FromMilliseconds(500);
+
+}  // namespace
+
+class AudioPlaybackSinkIosTest : public ::testing::Test {
+ protected:
+  void SetUp() override;
+  void TearDown() override;
+
+  void FeedStreamFormat();
+  void BlockAndRunOnAudioThread(base::OnceClosure closure);
+  void Sleep();
+
+  base::Thread audio_thread_{"Chromoting Audio"};
+  std::unique_ptr<FakeAsyncAudioDataSupplier> supplier_;
+  std::unique_ptr<AudioPlaybackSinkIos> sink_;
+};
+
+// Test fixture definitions
+
+void AudioPlaybackSinkIosTest::SetUp() {
+  audio_thread_.StartAndWaitForTesting();
+  supplier_ = std::make_unique<FakeAsyncAudioDataSupplier>();
+  sink_ = std::make_unique<AudioPlaybackSinkIos>();
+  sink_->SetDataSupplier(supplier_.get());
+}
+
+void AudioPlaybackSinkIosTest::TearDown() {
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    sink_.reset();
+    supplier_.reset();
+  }));
+  audio_thread_.Stop();
+}
+
+void AudioPlaybackSinkIosTest::FeedStreamFormat() {
+  sink_->ResetStreamFormat(kStreamFormat);
+}
+
+void AudioPlaybackSinkIosTest::BlockAndRunOnAudioThread(
+    base::OnceClosure closure) {
+  audio_thread_.task_runner()->PostTask(FROM_HERE, std::move(closure));
+  audio_thread_.FlushForTesting();
+}
+
+void AudioPlaybackSinkIosTest::Sleep() {
+  base::PlatformThread::Sleep(kBufferPlaybackTimeout);
+}
+
+// Test cases
+
+TEST_F(AudioPlaybackSinkIosTest, Init) {
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+    FeedStreamFormat();
+
+    // New requests have been enqueued immediately.
+    ASSERT_GT(supplier_->pending_requests_count(), 0u);
+  }));
+}
+
+TEST_F(AudioPlaybackSinkIosTest, NoLingeringRequestsAfterDestruction) {
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    FeedStreamFormat();
+    ASSERT_GT(supplier_->pending_requests_count(), 0u);
+
+    // Delete the audio sink.
+    sink_.reset();
+
+    // No lingering pending requests.
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+  }));
+}
+
+TEST_F(AudioPlaybackSinkIosTest, DestroyWhenPlaying) {
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    FeedStreamFormat();
+    ASSERT_GT(supplier_->pending_requests_count(), 0u);
+    supplier_->FulfillAllRequests();
+
+    // Delete the audio sink.
+    sink_.reset();
+
+    // No lingering pending requests.
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+  }));
+}
+
+TEST_F(AudioPlaybackSinkIosTest, BufferUnderrunScenario) {
+  size_t max_number_of_requests;
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+    FeedStreamFormat();
+    max_number_of_requests = supplier_->pending_requests_count();
+    ASSERT_GT(max_number_of_requests, 0u);
+    supplier_->FulfillAllRequests();
+    // Old buffers are returned. New request has not come yet.
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+  }));
+
+  // Wait for the sink to consume all buffers and return them to the supplier.
+  Sleep();
+
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    // Audio buffers should now be returned to the supplier. The AudioQueue
+    // should be stopped because of buffer underrun.
+    ASSERT_EQ(max_number_of_requests, supplier_->pending_requests_count());
+
+    supplier_->FulfillAllRequests();
+
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+  }));
+
+  // Wait for the sink to consume all buffers.
+  Sleep();
+
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    // Audio buffers should now be returned to the supplier. Buffer underrun
+    // again.
+    ASSERT_EQ(max_number_of_requests, supplier_->pending_requests_count());
+  }));
+}
+
+TEST_F(AudioPlaybackSinkIosTest, KeepFulfillingRequestsOneByOne) {
+  size_t max_number_of_requests;
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    supplier_->set_fulfill_requests_immediately(true);
+    FeedStreamFormat();
+    max_number_of_requests = supplier_->pending_requests_count();
+  }));
+
+  size_t number_of_fulfilled_requests = 0;
+
+  // Keep the queue running and verify that the number of fulfilled requests
+  // keeps increasing.
+  for (int i = 0; i < 5; i++) {
+    Sleep();
+
+    BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+      // Make sure the number of pending requests does not exceed
+      // |max_number_of_requests|.
+      ASSERT_LE(supplier_->pending_requests_count(), max_number_of_requests);
+
+      size_t new_number_of_fulfilled_requests =
+          supplier_->fulfilled_requests_count();
+      ASSERT_GT(new_number_of_fulfilled_requests, number_of_fulfilled_requests);
+      number_of_fulfilled_requests = new_number_of_fulfilled_requests;
+    }));
+  }
+}
+
+TEST_F(AudioPlaybackSinkIosTest, ChangeStreamFormat_NoPendingRequests) {
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+    FeedStreamFormat();
+    size_t max_number_of_requests = supplier_->pending_requests_count();
+    ASSERT_GT(max_number_of_requests, 0u);
+    supplier_->FulfillAllRequests();
+    // Old buffers are returned. New request has not come yet.
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+    // Change the sample rate to 48000 now.
+    AudioStreamFormat new_stream_format = {2, 2, 48000};
+    sink_->ResetStreamFormat(new_stream_format);
+
+    // New pending requests are enqueued.
+    ASSERT_EQ(max_number_of_requests, supplier_->pending_requests_count());
+  }));
+}
+
+TEST_F(AudioPlaybackSinkIosTest, ChangeStreamFormat_WithPendingRequests) {
+  size_t max_number_of_requests;
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+    FeedStreamFormat();
+    max_number_of_requests = supplier_->pending_requests_count();
+    ASSERT_GT(max_number_of_requests, 0u);
+    supplier_->FulfillAllRequests();
+    // Old buffers are returned. New request has not come yet.
+    ASSERT_EQ(0u, supplier_->pending_requests_count());
+  }));
+
+  // Sleep until new requests are enqueued.
+  Sleep();
+
+  BlockAndRunOnAudioThread(base::BindLambdaForTesting([&]() {
+    // Verify that new requests are enqueued.
+    ASSERT_EQ(max_number_of_requests, supplier_->pending_requests_count());
+
+    // Change the sample rate to 48000 now.
+    AudioStreamFormat new_stream_format = {2, 2, 48000};
+    sink_->ResetStreamFormat(new_stream_format);
+
+    // Same number of enqueued requests.
+    ASSERT_EQ(max_number_of_requests, supplier_->pending_requests_count());
+  }));
+}
+
+}  // namespace remoting
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 8852fd1..a7f4e76ed 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -274,7 +274,7 @@
       "//net/tools/testserver/",
       "//services/test/data",
       "//third_party/pyftpdlib/",
-      "//third_party/pywebsocket/",
+      "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
     ]
   }
diff --git a/services/tracing/public/cpp/trace_event_agent.cc b/services/tracing/public/cpp/trace_event_agent.cc
index 2623a650..d3427fc 100644
--- a/services/tracing/public/cpp/trace_event_agent.cc
+++ b/services/tracing/public/cpp/trace_event_agent.cc
@@ -90,18 +90,26 @@
 std::unique_ptr<TraceEventAgent> TraceEventAgent::Create(
     service_manager::Connector* connector,
     bool request_clock_sync_marker_on_android) {
+  std::unique_ptr<TraceEventAgent> new_agent;
+
   if (TracingUsesPerfettoBackend()) {
 #if defined(PERFETTO_AVAILABLE)
-    return std::make_unique<PerfettoTraceEventAgent>(
+    new_agent = std::make_unique<PerfettoTraceEventAgent>(
         connector, request_clock_sync_marker_on_android);
 #else
-    LOG(FATAL) << "Perfetto is not yet available for this platform.";
-    return nullptr;
+    LOG(ERROR) << "Perfetto is not yet available for this platform; falling "
+                  "back to using legacy TraceLog";
 #endif
-  } else {
-    return std::make_unique<LegacyTraceEventAgent>(
+  }
+
+  // Use legacy tracing if we're on an unsupported platform or the feature flag
+  // is disabled.
+  if (!new_agent) {
+    new_agent = std::make_unique<LegacyTraceEventAgent>(
         connector, request_clock_sync_marker_on_android);
   }
+
+  return new_agent;
 }
 
 TraceEventAgent::TraceEventAgent(service_manager::Connector* connector,
diff --git a/services/tracing/tracing_service.cc b/services/tracing/tracing_service.cc
index 726fc274..22c812e 100644
--- a/services/tracing/tracing_service.cc
+++ b/services/tracing/tracing_service.cc
@@ -45,6 +45,8 @@
 void TracingService::OnStart() {
   tracing_agent_registry_ = std::make_unique<AgentRegistry>();
 
+  bool enable_legacy_tracing = true;
+
   if (TracingUsesPerfettoBackend()) {
 #if defined(PERFETTO_SERVICE_AVAILABLE)
     perfetto_service_ = std::make_unique<tracing::PerfettoService>();
@@ -59,10 +61,13 @@
         base::BindRepeating(&PerfettoTracingCoordinator::BindCoordinatorRequest,
                             base::Unretained(perfetto_coordinator.get())));
     perfetto_tracing_coordinator_ = std::move(perfetto_coordinator);
-#else
-    LOG(FATAL) << "Perfetto is not yet available for this platform.";
+    enable_legacy_tracing = false;
 #endif
-  } else {
+  }
+
+  // Use legacy tracing if we're on an unsupported platform or the feature flag
+  // is disabled.
+  if (enable_legacy_tracing) {
     auto tracing_coordinator =
         std::make_unique<Coordinator>(tracing_agent_registry_.get());
     registry_.AddInterface(
diff --git a/services/ui/ws2/BUILD.gn b/services/ui/ws2/BUILD.gn
index b171a50e..e85af2f0 100644
--- a/services/ui/ws2/BUILD.gn
+++ b/services/ui/ws2/BUILD.gn
@@ -204,6 +204,7 @@
     "//ui/aura:test_support",
     "//ui/events:test_support",
     "//ui/platform_window",
+    "//ui/wm",
   ]
 
   data_deps = [
diff --git a/services/ui/ws2/client_root.cc b/services/ui/ws2/client_root.cc
index 5834462..3d5b6d0d 100644
--- a/services/ui/ws2/client_root.cc
+++ b/services/ui/ws2/client_root.cc
@@ -46,9 +46,7 @@
     window_->GetHost()->RemoveObserver(this);
 
   viz::HostFrameSinkManager* host_frame_sink_manager =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetHostFrameSinkManager();
+      window_->env()->context_factory_private()->GetHostFrameSinkManager();
   host_frame_sink_manager->InvalidateFrameSinkId(
       server_window->frame_sink_id());
 }
@@ -56,9 +54,7 @@
 void ClientRoot::RegisterVizEmbeddingSupport() {
   // This function should only be called once.
   viz::HostFrameSinkManager* host_frame_sink_manager =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetHostFrameSinkManager();
+      window_->env()->context_factory_private()->GetHostFrameSinkManager();
   viz::FrameSinkId frame_sink_id =
       ServerWindow::GetMayBeNull(window_)->frame_sink_id();
   host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id, this);
@@ -115,7 +111,8 @@
     return;
   }
 
-  HandleBoundsOrScaleFactorChange(window_->bounds());
+  HandleBoundsOrScaleFactorChange(is_top_level_ ? window_->GetBoundsInScreen()
+                                                : window_->bounds());
 }
 
 void ClientRoot::HandleBoundsOrScaleFactorChange(const gfx::Rect& old_bounds) {
@@ -125,7 +122,7 @@
   // why this always notifies the client.
   window_tree_->window_tree_client_->OnWindowBoundsChanged(
       window_tree_->TransportIdForWindow(window_), old_bounds,
-      window_->bounds(),
+      is_top_level_ ? window_->GetBoundsInScreen() : window_->bounds(),
       ServerWindow::GetMayBeNull(window_)->local_surface_id());
 }
 
diff --git a/services/ui/ws2/injected_event_handler.cc b/services/ui/ws2/injected_event_handler.cc
index 66c99e5..56f9d1b9 100644
--- a/services/ui/ws2/injected_event_handler.cc
+++ b/services/ui/ws2/injected_event_handler.cc
@@ -20,7 +20,7 @@
     : window_service_(window_service), window_tree_host_(window_tree_host) {
   window_service_->AddObserver(this);
   window_tree_host_->window()->AddObserver(this);
-  aura::Env::GetInstance()->AddWindowEventDispatcherObserver(this);
+  window_tree_host_->window()->env()->AddWindowEventDispatcherObserver(this);
 }
 
 InjectedEventHandler::~InjectedEventHandler() {
@@ -56,7 +56,7 @@
   if (!window_service_)
     return;
 
-  aura::Env::GetInstance()->RemoveWindowEventDispatcherObserver(this);
+  window_tree_host_->window()->env()->RemoveWindowEventDispatcherObserver(this);
   window_tree_host_->window()->RemoveObserver(this);
   window_service_->RemoveObserver(this);
   window_service_ = nullptr;
diff --git a/services/ui/ws2/pointer_watcher.cc b/services/ui/ws2/pointer_watcher.cc
index 326f301f..9536094 100644
--- a/services/ui/ws2/pointer_watcher.cc
+++ b/services/ui/ws2/pointer_watcher.cc
@@ -4,6 +4,7 @@
 
 #include "services/ui/ws2/pointer_watcher.h"
 
+#include "services/ui/ws2/window_service.h"
 #include "services/ui/ws2/window_tree.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -26,11 +27,11 @@
 }
 
 PointerWatcher::PointerWatcher(WindowTree* tree) : tree_(tree) {
-  aura::Env::GetInstance()->AddWindowEventDispatcherObserver(this);
+  tree->window_service()->env()->AddWindowEventDispatcherObserver(this);
 }
 
 PointerWatcher::~PointerWatcher() {
-  aura::Env::GetInstance()->RemoveWindowEventDispatcherObserver(this);
+  tree_->window_service()->env()->RemoveWindowEventDispatcherObserver(this);
 }
 
 bool PointerWatcher::DoesEventMatch(const ui::Event& event) const {
diff --git a/services/ui/ws2/server_window.cc b/services/ui/ws2/server_window.cc
index 73d22ac..b7534af 100644
--- a/services/ui/ws2/server_window.cc
+++ b/services/ui/ws2/server_window.cc
@@ -494,9 +494,7 @@
     viz::mojom::CompositorFrameSinkClientPtr client) {
   attached_compositor_frame_sink_ = true;
   viz::HostFrameSinkManager* host_frame_sink_manager =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetHostFrameSinkManager();
+      window_->env()->context_factory_private()->GetHostFrameSinkManager();
   host_frame_sink_manager->CreateCompositorFrameSink(
       frame_sink_id_, std::move(compositor_frame_sink), std::move(client));
 }
diff --git a/services/ui/ws2/user_activity_monitor.cc b/services/ui/ws2/user_activity_monitor.cc
index 07d2f49..a2220061 100644
--- a/services/ui/ws2/user_activity_monitor.cc
+++ b/services/ui/ws2/user_activity_monitor.cc
@@ -16,17 +16,18 @@
 namespace ws2 {
 
 UserActivityMonitor::UserActivityMonitor(
+    aura::Env* env,
     std::unique_ptr<const base::TickClock> clock)
-    : now_clock_(std::move(clock)) {
+    : env_(env), now_clock_(std::move(clock)) {
   if (!now_clock_)
     now_clock_ = std::make_unique<base::DefaultTickClock>();
   last_activity_ = now_clock_->NowTicks();
 
-  aura::Env::GetInstance()->AddPreTargetHandler(this);
+  env_->AddPreTargetHandler(this);
 }
 
 UserActivityMonitor::~UserActivityMonitor() {
-  aura::Env::GetInstance()->RemovePreTargetHandler(this);
+  env_->RemovePreTargetHandler(this);
 }
 
 void UserActivityMonitor::AddBinding(
diff --git a/services/ui/ws2/user_activity_monitor.h b/services/ui/ws2/user_activity_monitor.h
index ca8dae34..85f3159 100644
--- a/services/ui/ws2/user_activity_monitor.h
+++ b/services/ui/ws2/user_activity_monitor.h
@@ -17,6 +17,10 @@
 #include "services/ui/public/interfaces/user_activity_monitor.mojom.h"
 #include "ui/events/event_handler.h"
 
+namespace aura {
+class Env;
+}
+
 namespace ui {
 namespace ws2 {
 
@@ -33,6 +37,7 @@
   // |now_clock| is used to get the timestamp. If |now_clock| is nullptr, then
   // DefaultTickClock is used.
   explicit UserActivityMonitor(
+      aura::Env* env,
       std::unique_ptr<const base::TickClock> now_clock = nullptr);
   ~UserActivityMonitor() override;
 
@@ -61,6 +66,8 @@
   void OnActivityObserverDisconnected(mojom::UserActivityObserver* observer);
   void OnIdleObserverDisconnected(mojom::UserIdleObserver* observer);
 
+  aura::Env* env_;
+
   mojo::BindingSet<mojom::UserActivityMonitor> bindings_;
   std::unique_ptr<const base::TickClock> now_clock_;
 
diff --git a/services/ui/ws2/user_activity_monitor_unittest.cc b/services/ui/ws2/user_activity_monitor_unittest.cc
index c0032b4..9e4cd0d 100644
--- a/services/ui/ws2/user_activity_monitor_unittest.cc
+++ b/services/ui/ws2/user_activity_monitor_unittest.cc
@@ -106,7 +106,7 @@
     env_ = aura::Env::CreateInstance(aura::Env::Mode::LOCAL);
     TaskRunnerTestBase::SetUp();
     monitor_ = std::make_unique<UserActivityMonitor>(
-        task_runner()->DeprecatedGetMockTickClock());
+        env_.get(), task_runner()->DeprecatedGetMockTickClock());
   }
 
   std::unique_ptr<aura::Env> env_;
diff --git a/services/ui/ws2/window_service.cc b/services/ui/ws2/window_service.cc
index 9bc55fd..7978057 100644
--- a/services/ui/ws2/window_service.cc
+++ b/services/ui/ws2/window_service.cc
@@ -33,12 +33,14 @@
     WindowServiceDelegate* delegate,
     std::unique_ptr<GpuInterfaceProvider> gpu_interface_provider,
     aura::client::FocusClient* focus_client,
-    bool decrement_client_ids)
+    bool decrement_client_ids,
+    aura::Env* env)
     : delegate_(delegate),
+      env_(env ? env : aura::Env::GetInstance()),
       gpu_interface_provider_(std::move(gpu_interface_provider)),
       screen_provider_(std::make_unique<ScreenProvider>()),
       focus_client_(focus_client),
-      user_activity_monitor_(std::make_unique<UserActivityMonitor>()),
+      user_activity_monitor_(std::make_unique<UserActivityMonitor>(env_)),
       next_client_id_(decrement_client_ids ? kInitialClientIdDecrement
                                            : kInitialClientId),
       decrement_client_ids_(decrement_client_ids),
diff --git a/services/ui/ws2/window_service.h b/services/ui/ws2/window_service.h
index 451f7465..7d0a5ffc 100644
--- a/services/ui/ws2/window_service.h
+++ b/services/ui/ws2/window_service.h
@@ -30,6 +30,7 @@
 #include "ui/base/mojo/clipboard.mojom.h"
 
 namespace aura {
+class Env;
 class Window;
 namespace client {
 class FocusClient;
@@ -74,7 +75,8 @@
   WindowService(WindowServiceDelegate* delegate,
                 std::unique_ptr<GpuInterfaceProvider> gpu_support,
                 aura::client::FocusClient* focus_client,
-                bool decrement_client_ids = false);
+                bool decrement_client_ids = false,
+                aura::Env* env = nullptr);
   ~WindowService() override;
 
   // Gets the ServerWindow for |window|, creating if necessary.
@@ -97,6 +99,8 @@
   // Whether |window| hosts a remote client.
   static bool HasRemoteClient(const aura::Window* window);
 
+  aura::Env* env() { return env_; }
+
   void AddObserver(WindowServiceObserver* observer);
   void RemoveObserver(WindowServiceObserver* observer);
   base::ObserverList<WindowServiceObserver>& observers() { return observers_; }
@@ -168,6 +172,8 @@
 
   WindowServiceDelegate* delegate_;
 
+  aura::Env* env_;
+
   // GpuInterfaceProvider may be null in tests.
   std::unique_ptr<GpuInterfaceProvider> gpu_interface_provider_;
 
diff --git a/services/ui/ws2/window_tree.cc b/services/ui/ws2/window_tree.cc
index baeb995..e7dc2dfa 100644
--- a/services/ui/ws2/window_tree.cc
+++ b/services/ui/ws2/window_tree.cc
@@ -26,6 +26,7 @@
 #include "services/ui/ws2/window_service_delegate.h"
 #include "services/ui/ws2/window_service_observer.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/mus/os_exchange_data_provider_mus.h"
@@ -530,7 +531,8 @@
   window_data->transient_parent_id =
       transient_parent ? TransportIdForWindow(transient_parent)
                        : kInvalidTransportId;
-  window_data->bounds = window->bounds();
+  window_data->bounds =
+      IsTopLevel(window) ? window->GetBoundsInScreen() : window->bounds();
   window_data->properties =
       window_service_->property_converter()->GetTransportProperties(window);
   window_data->visible = window->TargetVisibility();
@@ -604,8 +606,9 @@
   const bool is_top_level = false;
   // WindowDelegateImpl deletes itself when |window| is destroyed.
   WindowDelegateImpl* window_delegate = new WindowDelegateImpl();
-  std::unique_ptr<aura::Window> window_ptr =
-      std::make_unique<aura::Window>(window_delegate);
+  std::unique_ptr<aura::Window> window_ptr = std::make_unique<aura::Window>(
+      window_delegate, aura::client::WINDOW_TYPE_UNKNOWN,
+      window_service_->env());
   window_delegate->set_window(window_ptr.get());
   aura::Window* window = AddClientCreatedWindow(client_window_id, is_top_level,
                                                 std::move(window_ptr));
@@ -1009,8 +1012,10 @@
   }
 
   ServerWindow* server_window = ServerWindow::GetMayBeNull(window);
+  const gfx::Rect original_bounds =
+      IsTopLevel(window) ? window->GetBoundsInScreen() : window->bounds();
 
-  if (window->bounds() == bounds &&
+  if (original_bounds == bounds &&
       server_window->local_surface_id() == local_surface_id) {
     return true;
   }
@@ -1021,8 +1026,15 @@
   if (IsLocalSurfaceIdAssignedByClient(window))
     server_window->set_local_surface_id(local_surface_id);
 
-  const gfx::Rect original_bounds = window->bounds();
-  window->SetBounds(bounds);
+  aura::client::ScreenPositionClient* screen_position_client =
+      aura::client::GetScreenPositionClient(window->GetRootWindow());
+  if (IsTopLevel(window) && screen_position_client) {
+    display::Display dst_display =
+        display::Screen::GetScreen()->GetDisplayMatching(bounds);
+    screen_position_client->SetBounds(window, bounds, dst_display);
+  } else {
+    window->SetBounds(bounds);
+  }
   if (!change.window())
     return true;  // Return value doesn't matter if window destroyed.
 
@@ -1732,7 +1744,7 @@
   }
 
   if (source == ui::mojom::MoveLoopSource::MOUSE &&
-      !aura::Env::GetInstance()->IsMouseButtonDown()) {
+      !window->env()->IsMouseButtonDown()) {
     DVLOG(1) << "PerformWindowMove failed (mouse not down)";
     window_tree_client_->OnChangeCompleted(change_id, false);
     return;
diff --git a/services/ui/ws2/window_tree_unittest.cc b/services/ui/ws2/window_tree_unittest.cc
index ce7d4c8..02914cf 100644
--- a/services/ui/ws2/window_tree_unittest.cc
+++ b/services/ui/ws2/window_tree_unittest.cc
@@ -30,6 +30,7 @@
 #include "ui/aura/window_tracker.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/wm/core/capture_controller.h"
+#include "ui/wm/core/default_screen_position_client.h"
 #include "ui/wm/core/focus_controller.h"
 #include "ui/wm/core/window_util.h"
 
@@ -85,6 +86,38 @@
   *result_value = actual_result;
 }
 
+// A screen position client with a fixed screen offset applied via SetBounds.
+class TestScreenPositionClient : public wm::DefaultScreenPositionClient {
+ public:
+  explicit TestScreenPositionClient(const gfx::Vector2d& offset)
+      : offset_(offset) {}
+  ~TestScreenPositionClient() override = default;
+
+  // wm::DefaultScreenPositionClient:
+  void ConvertPointToScreen(const aura::Window* window,
+                            gfx::PointF* point) override {
+    wm::DefaultScreenPositionClient::ConvertPointToScreen(window, point);
+    *point += offset_;
+  }
+  void ConvertPointFromScreen(const aura::Window* window,
+                              gfx::PointF* point) override {
+    *point -= offset_;
+    wm::DefaultScreenPositionClient::ConvertPointFromScreen(window, point);
+  }
+  void SetBounds(aura::Window* window,
+                 const gfx::Rect& bounds,
+                 const display::Display& display) override {
+    EXPECT_EQ(display, display::Screen::GetScreen()->GetPrimaryDisplay());
+    gfx::Rect offset_bounds = bounds;
+    offset_bounds.Offset(-offset_);
+    wm::DefaultScreenPositionClient::SetBounds(window, offset_bounds, display);
+  }
+
+ private:
+  const gfx::Vector2d offset_;
+  DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient);
+};
+
 TEST(WindowTreeTest, NewWindow) {
   WindowServiceTestSetup setup;
   EXPECT_TRUE(setup.changes()->empty());
@@ -136,15 +169,15 @@
       setup.window_tree_test_helper()->NewTopLevelWindow();
   setup.changes()->clear();
 
-  const gfx::Rect bounds_from_client = gfx::Rect(1, 2, 300, 400);
+  const gfx::Rect bounds_from_client = gfx::Rect(100, 200, 300, 400);
   setup.window_tree_test_helper()->SetWindowBoundsWithAck(
       top_level, bounds_from_client, 2);
-  EXPECT_EQ(bounds_from_client, top_level->bounds());
+  EXPECT_EQ(bounds_from_client, top_level->GetBoundsInScreen());
   ASSERT_EQ(2u, setup.changes()->size());
   {
     const Change& change = (*setup.changes())[0];
     EXPECT_EQ(CHANGE_TYPE_NODE_BOUNDS_CHANGED, change.type);
-    EXPECT_EQ(top_level->bounds(), change.bounds2);
+    EXPECT_EQ(top_level->GetBoundsInScreen(), change.bounds2);
     EXPECT_TRUE(change.local_surface_id);
     setup.changes()->erase(setup.changes()->begin());
   }
@@ -179,6 +212,33 @@
   // And because the layout manager changed the bounds the result is false.
   EXPECT_EQ("ChangeCompleted id=3 success=false",
             ChangeToDescription((*setup.changes())[1]));
+  setup.changes()->clear();
+
+  // Install a screen position client with a non-zero screen bounds offset.
+  gfx::Vector2d screen_offset(10, 20);
+  TestScreenPositionClient screen_position_client(screen_offset);
+  aura::client::SetScreenPositionClient(setup.aura_test_helper()->root_window(),
+                                        &screen_position_client);
+
+  // Tests that top-level window bounds are set in screen coordinates.
+  setup.window_tree_test_helper()->SetWindowBoundsWithAck(
+      top_level, bounds_from_client, 4);
+  EXPECT_EQ(bounds_from_client, top_level->GetBoundsInScreen());
+  EXPECT_EQ(bounds_from_client - screen_offset, top_level->bounds());
+  ASSERT_EQ(2u, setup.changes()->size());
+  {
+    const Change& change = (*setup.changes())[0];
+    EXPECT_EQ(CHANGE_TYPE_NODE_BOUNDS_CHANGED, change.type);
+    EXPECT_EQ(top_level->GetBoundsInScreen(), change.bounds2);
+    EXPECT_TRUE(change.local_surface_id);
+    setup.changes()->erase(setup.changes()->begin());
+  }
+  // See comments in WindowTree::SetBoundsImpl() for why this returns false.
+  EXPECT_EQ("ChangeCompleted id=4 success=false",
+            SingleChangeToDescription(*setup.changes()));
+
+  aura::client::SetScreenPositionClient(setup.aura_test_helper()->root_window(),
+                                        nullptr);
 }
 
 TEST(WindowTreeTest, SetTopLevelWindowBoundsFailsForSameSize) {
diff --git a/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc b/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
index 4753d2b..587223cc 100644
--- a/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
+++ b/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
@@ -79,9 +79,19 @@
   ProducerSharesBufferHandle(kArbitraryBufferId2);
 
   base::RunLoop wait_loop;
-  EXPECT_CALL(*mock_receiver_1_, DoOnNewBuffer(kArbitraryBufferId1, _));
+  int buffer_received_count = 0;
+  EXPECT_CALL(*mock_receiver_1_, DoOnNewBuffer(kArbitraryBufferId1, _))
+      .WillOnce(InvokeWithoutArgs([&wait_loop, &buffer_received_count]() {
+        buffer_received_count++;
+        if (buffer_received_count == 2)
+          wait_loop.Quit();
+      }));
   EXPECT_CALL(*mock_receiver_1_, DoOnNewBuffer(kArbitraryBufferId2, _))
-      .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
+      .WillOnce(InvokeWithoutArgs([&wait_loop, &buffer_received_count]() {
+        buffer_received_count++;
+        if (buffer_received_count == 2)
+          wait_loop.Quit();
+      }));
   Receiver1Connects();
   wait_loop.Run();
 }
diff --git a/storage/browser/blob/blob_reader.h b/storage/browser/blob/blob_reader.h
index 61beacb..947d13a 100644
--- a/storage/browser/blob/blob_reader.h
+++ b/storage/browser/blob/blob_reader.h
@@ -191,7 +191,7 @@
   int BytesReadCompleted();
 
   // Returns a FileStreamReader for a blob item at |index|.
-  // If the item at |index| is not of file this returns NULL.
+  // If the item at |index| is not of file this returns nullptr.
   FileStreamReader* GetOrCreateFileReaderAtIndex(size_t index);
   // If the reader is null, then this basically performs a delete operation.
   void SetFileReaderAtIndex(size_t index,
diff --git a/storage/browser/blob/blob_url_request_job_factory.cc b/storage/browser/blob/blob_url_request_job_factory.cc
index c8f8345d..270cc8f 100644
--- a/storage/browser/blob/blob_url_request_job_factory.cc
+++ b/storage/browser/blob/blob_url_request_job_factory.cc
@@ -95,7 +95,7 @@
   if (blob_data_handle)
     return blob_data_handle;
   if (!context_.get())
-    return NULL;
+    return nullptr;
 
   // Support looking up based on uuid, the FeedbackExtensionAPI relies on this.
   // TODO(michaeln): Replace this use case and others like it with a BlobReader
@@ -103,7 +103,7 @@
   const std::string kPrefix("blob:uuid/");
   if (!base::StartsWith(request->url().spec(), kPrefix,
                         base::CompareCase::SENSITIVE))
-    return NULL;
+    return nullptr;
   std::string uuid = request->url().spec().substr(kPrefix.length());
   std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(uuid);
   BlobDataHandle* handle_ptr = handle.get();
diff --git a/storage/browser/blob/shareable_file_reference.cc b/storage/browser/blob/shareable_file_reference.cc
index 9b5c5ce..e147ccfc 100644
--- a/storage/browser/blob/shareable_file_reference.cc
+++ b/storage/browser/blob/shareable_file_reference.cc
@@ -72,7 +72,7 @@
     const base::FilePath& path) {
   ShareableFileMap::iterator found = g_file_map.Get().Find(path);
   ShareableFileReference* reference =
-      (found == g_file_map.Get().End()) ? NULL : found->second;
+      (found == g_file_map.Get().End()) ? nullptr : found->second;
   return scoped_refptr<ShareableFileReference>(reference);
 }
 
@@ -120,12 +120,12 @@
 #if DCHECK_IS_ON()
   g_file_map.Get().AssertCalledOnValidSequence();
 #endif  // DCHECK_IS_ON()
-  scoped_file_.AddScopeOutCallback(std::move(callback), NULL);
+  scoped_file_.AddScopeOutCallback(std::move(callback), nullptr);
 }
 
 ShareableFileReference::ShareableFileReference(ScopedFile scoped_file)
     : scoped_file_(std::move(scoped_file)) {
-  DCHECK(g_file_map.Get().Find(path())->second == NULL);
+  DCHECK(g_file_map.Get().Find(path())->second == nullptr);
 }
 
 ShareableFileReference::~ShareableFileReference() {
diff --git a/storage/browser/blob/shareable_file_reference.h b/storage/browser/blob/shareable_file_reference.h
index 7b935a0f..1e10c58 100644
--- a/storage/browser/blob/shareable_file_reference.h
+++ b/storage/browser/blob/shareable_file_reference.h
@@ -26,7 +26,7 @@
   };
 
   // Returns a ShareableFileReference for the given path, if no reference
-  // for this path exists returns NULL.
+  // for this path exists returns nullptr.
   static scoped_refptr<ShareableFileReference> Get(const base::FilePath& path);
 
   // Returns a ShareableFileReference for the given path, creating a new
@@ -43,7 +43,7 @@
   // If there's a pre-existing reference for the path, the scope out policy
   // and scope-out-callbacks of the given |scoped_file| is ignored.
   // If the given scoped_file has an empty path (e.g. maybe already
-  // released) this returns NULL reference.
+  // released) this returns nullptr reference.
   //
   // TODO(kinuko): Make sure if this behavior is ok, we could alternatively
   // merge callbacks to the existing one.
diff --git a/storage/browser/fileapi/copy_or_move_file_validator.h b/storage/browser/fileapi/copy_or_move_file_validator.h
index e1fe721..e2c05cc2 100644
--- a/storage/browser/fileapi/copy_or_move_file_validator.h
+++ b/storage/browser/fileapi/copy_or_move_file_validator.h
@@ -41,7 +41,7 @@
  public:
   virtual ~CopyOrMoveFileValidatorFactory() {}
 
-  // This method must always return a non-NULL validator. |src_url| is needed
+  // This method must always return a non-null validator. |src_url| is needed
   // in addition to |platform_path| because in the obfuscated file system
   // case, |platform_path| will be an obfuscated filename and extension.
   virtual CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
diff --git a/storage/browser/fileapi/copy_or_move_file_validator_unittest.cc b/storage/browser/fileapi/copy_or_move_file_validator_unittest.cc
index 37ce98c5..2d1cd422 100644
--- a/storage/browser/fileapi/copy_or_move_file_validator_unittest.cc
+++ b/storage/browser/fileapi/copy_or_move_file_validator_unittest.cc
@@ -56,7 +56,7 @@
       : origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
 
   ~CopyOrMoveFileValidatorTestHelper() {
-    file_system_context_ = NULL;
+    file_system_context_ = nullptr;
     base::RunLoop().RunUntilIdle();
   }
 
@@ -64,7 +64,7 @@
     ASSERT_TRUE(base_.CreateUniqueTempDir());
     base::FilePath base_dir = base_.GetPath();
 
-    file_system_context_ = CreateFileSystemContextForTesting(NULL, base_dir);
+    file_system_context_ = CreateFileSystemContextForTesting(nullptr, base_dir);
 
     // Set up TestFileSystemBackend to require CopyOrMoveFileValidator.
     storage::FileSystemBackend* test_file_system_backend =
diff --git a/storage/browser/fileapi/copy_or_move_operation_delegate.cc b/storage/browser/fileapi/copy_or_move_operation_delegate.cc
index 3d66867..0756693 100644
--- a/storage/browser/fileapi/copy_or_move_operation_delegate.cc
+++ b/storage/browser/fileapi/copy_or_move_operation_delegate.cc
@@ -224,7 +224,7 @@
       return;
     }
 
-    // |validator_| is NULL when the destination filesystem does not do
+    // |validator_| is nullptr when the destination filesystem does not do
     // validation.
     if (!validator_) {
       // No validation is needed.
diff --git a/storage/browser/fileapi/copy_or_move_operation_delegate_unittest.cc b/storage/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
index f70d69c1..48684f6 100644
--- a/storage/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
+++ b/storage/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
@@ -186,10 +186,10 @@
             base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
 
   ~CopyOrMoveOperationTestHelper() {
-    file_system_context_ = NULL;
+    file_system_context_ = nullptr;
     quota_manager_proxy_->SimulateQuotaManagerDestroyed();
-    quota_manager_ = NULL;
-    quota_manager_proxy_ = NULL;
+    quota_manager_ = nullptr;
+    quota_manager_proxy_ = nullptr;
     scoped_task_environment_.RunUntilIdle();
   }
 
@@ -208,7 +208,7 @@
     quota_manager_ =
         new MockQuotaManager(false /* is_incognito */, base_dir,
                              base::ThreadTaskRunnerHandle::Get().get(),
-                             NULL /* special storage policy */);
+                             nullptr /* special storage policy */);
     quota_manager_proxy_ = new MockQuotaManagerProxy(
         quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
     file_system_context_ =
@@ -252,13 +252,13 @@
 
   int64_t GetSourceUsage() {
     int64_t usage = 0;
-    GetUsageAndQuota(src_type_, &usage, NULL);
+    GetUsageAndQuota(src_type_, &usage, nullptr);
     return usage;
   }
 
   int64_t GetDestUsage() {
     int64_t usage = 0;
-    GetUsageAndQuota(dest_type_, &usage, NULL);
+    GetUsageAndQuota(dest_type_, &usage, nullptr);
     return usage;
   }
 
diff --git a/storage/browser/fileapi/dragged_file_util.cc b/storage/browser/fileapi/dragged_file_util.cc
index e9b432a..5ddd394 100644
--- a/storage/browser/fileapi/dragged_file_util.cc
+++ b/storage/browser/fileapi/dragged_file_util.cc
@@ -69,7 +69,8 @@
   if (url.path().empty()) {
     // The root directory case.
     // For now we leave three time fields (modified/accessed/creation time)
-    // NULL as it is not really clear what to be set for this virtual directory.
+    // nullptr as it is not really clear what to be set for this virtual
+    // directory.
     // TODO(kinuko): Maybe we want to set the time when this filesystem is
     // created (i.e. when the files/directories are dropped).
     file_info->is_directory = true;
diff --git a/storage/browser/fileapi/dragged_file_util_unittest.cc b/storage/browser/fileapi/dragged_file_util_unittest.cc
index 7f0f5fe..994f0a04 100644
--- a/storage/browser/fileapi/dragged_file_util_unittest.cc
+++ b/storage/browser/fileapi/dragged_file_util_unittest.cc
@@ -110,7 +110,7 @@
     SimulateDropFiles();
 
     file_system_context_ = CreateFileSystemContextForTesting(
-        NULL /* quota_manager */, partition_dir_.GetPath());
+        nullptr /* quota_manager */, partition_dir_.GetPath());
 
     isolated_context()->AddReference(filesystem_id_);
   }
@@ -270,7 +270,7 @@
         base::FilePath root = root_path().Append(
             kRootPaths[(root_path_index++) % arraysize(kRootPaths)]);
         toplevel_root_map_[toplevel] = root;
-        toplevels.AddPath(root.Append(path), NULL);
+        toplevels.AddPath(root.Append(path), nullptr);
       }
 
       SetUpOneFileSystemTestCase(toplevel_root_map_[toplevel], test_case);
diff --git a/storage/browser/fileapi/dump_file_system.cc b/storage/browser/fileapi/dump_file_system.cc
index 03595909..d7c5930 100644
--- a/storage/browser/fileapi/dump_file_system.cc
+++ b/storage/browser/fileapi/dump_file_system.cc
@@ -80,7 +80,7 @@
   if (!base::DirectoryExists(origin_dir))
     return;
 
-  SandboxDirectoryDatabase directory_db(origin_dir, NULL);
+  SandboxDirectoryDatabase directory_db(origin_dir, nullptr);
   SandboxDirectoryDatabase::FileId root_id;
   if (!directory_db.GetFileWithPath(StringToFilePath("/"), &root_id))
     return;
@@ -143,7 +143,7 @@
         SandboxPrioritizedOriginDatabase::kPrimaryDirectory);
   }
 
-  SandboxOriginDatabase origin_db(file_system_dir, NULL);
+  SandboxOriginDatabase origin_db(file_system_dir, nullptr);
   base::FilePath origin_dir;
   if (!origin_db.HasOriginPath(origin_name)) {
     ShowMessageAndExit("Origin " + origin_name + " is not in " +
@@ -165,7 +165,7 @@
 }
 
 static void DumpFileSystem(const base::FilePath& file_system_dir) {
-  SandboxOriginDatabase origin_db(file_system_dir, NULL);
+  SandboxOriginDatabase origin_db(file_system_dir, nullptr);
   std::vector<SandboxOriginDatabase::OriginRecord> origins;
   origin_db.ListAllOrigins(&origins);
   for (size_t i = 0; i < origins.size(); i++) {
diff --git a/storage/browser/fileapi/external_mount_points_unittest.cc b/storage/browser/fileapi/external_mount_points_unittest.cc
index 59be862..7e6007e 100644
--- a/storage/browser/fileapi/external_mount_points_unittest.cc
+++ b/storage/browser/fileapi/external_mount_points_unittest.cc
@@ -37,76 +37,76 @@
     const base::FilePath::CharType* const path;
     // Whether the mount point registration should succeed.
     bool success;
-    // Path returned by GetRegisteredPath. NULL if the method is expected to
+    // Path returned by GetRegisteredPath. nullptr if the method is expected to
     // fail.
     const base::FilePath::CharType* const registered_path;
   };
 
   const TestCase kTestCases[] = {
     // Valid mount point.
-    { "test", DRIVE FPL("/foo/test"), true, DRIVE FPL("/foo/test") },
+    {"test", DRIVE FPL("/foo/test"), true, DRIVE FPL("/foo/test")},
     // Valid mount point with only one path component.
-    { "bbb", DRIVE FPL("/bbb"), true, DRIVE FPL("/bbb") },
+    {"bbb", DRIVE FPL("/bbb"), true, DRIVE FPL("/bbb")},
     // Existing mount point path is substring of the mount points path.
-    { "test11", DRIVE FPL("/foo/test11"), true, DRIVE FPL("/foo/test11") },
+    {"test11", DRIVE FPL("/foo/test11"), true, DRIVE FPL("/foo/test11")},
     // Path substring of an existing path.
-    { "test1", DRIVE FPL("/foo/test1"), true, DRIVE FPL("/foo/test1") },
+    {"test1", DRIVE FPL("/foo/test1"), true, DRIVE FPL("/foo/test1")},
     // Empty mount point name and path.
-    { "", DRIVE FPL(""), false, NULL },
+    {"", DRIVE FPL(""), false, nullptr},
     // Empty mount point name.
-    { "", DRIVE FPL("/ddd"), false, NULL },
+    {"", DRIVE FPL("/ddd"), false, nullptr},
     // Empty mount point path.
-    { "empty_path", FPL(""), true, FPL("") },
+    {"empty_path", FPL(""), true, FPL("")},
     // Name different from path's base name.
-    { "not_base_name", DRIVE FPL("/x/y/z"), true, DRIVE FPL("/x/y/z") },
+    {"not_base_name", DRIVE FPL("/x/y/z"), true, DRIVE FPL("/x/y/z")},
     // References parent.
-    { "invalid", DRIVE FPL("../foo/invalid"), false, NULL },
+    {"invalid", DRIVE FPL("../foo/invalid"), false, nullptr},
     // Relative path.
-    { "relative", DRIVE FPL("foo/relative"), false, NULL },
+    {"relative", DRIVE FPL("foo/relative"), false, nullptr},
     // Existing mount point path.
-    { "path_exists", DRIVE FPL("/foo/test"), false, NULL },
+    {"path_exists", DRIVE FPL("/foo/test"), false, nullptr},
     // Mount point with the same name exists.
-    { "test", DRIVE FPL("/foo/a/test_name_exists"), false,
-      DRIVE FPL("/foo/test") },
+    {"test", DRIVE FPL("/foo/a/test_name_exists"), false,
+     DRIVE FPL("/foo/test")},
     // Child of an existing mount point.
-    { "a1", DRIVE FPL("/foo/test/a"), false, NULL },
+    {"a1", DRIVE FPL("/foo/test/a"), false, nullptr},
     // Parent of an existing mount point.
-    { "foo1", DRIVE FPL("/foo"), false, NULL },
+    {"foo1", DRIVE FPL("/foo"), false, nullptr},
     // Bit bigger depth.
-    { "g", DRIVE FPL("/foo/a/b/c/d/e/f/g"), true,
-      DRIVE FPL("/foo/a/b/c/d/e/f/g") },
+    {"g", DRIVE FPL("/foo/a/b/c/d/e/f/g"), true,
+     DRIVE FPL("/foo/a/b/c/d/e/f/g")},
     // Sibling mount point (with similar name) exists.
-    { "ff", DRIVE FPL("/foo/a/b/c/d/e/ff"), true,
-       DRIVE FPL("/foo/a/b/c/d/e/ff") },
+    {"ff", DRIVE FPL("/foo/a/b/c/d/e/ff"), true,
+     DRIVE FPL("/foo/a/b/c/d/e/ff")},
     // Lexicographically last among existing mount points.
-    { "yyy", DRIVE FPL("/zzz/yyy"), true, DRIVE FPL("/zzz/yyy") },
+    {"yyy", DRIVE FPL("/zzz/yyy"), true, DRIVE FPL("/zzz/yyy")},
     // Parent of the lexicographically last mount point.
-    { "zzz1", DRIVE FPL("/zzz"), false, NULL },
+    {"zzz1", DRIVE FPL("/zzz"), false, nullptr},
     // Child of the lexicographically last mount point.
-    { "xxx1", DRIVE FPL("/zzz/yyy/xxx"), false, NULL },
+    {"xxx1", DRIVE FPL("/zzz/yyy/xxx"), false, nullptr},
     // Lexicographically first among existing mount points.
-    { "b", DRIVE FPL("/a/b"), true, DRIVE FPL("/a/b") },
+    {"b", DRIVE FPL("/a/b"), true, DRIVE FPL("/a/b")},
     // Parent of lexicographically first mount point.
-    { "a2", DRIVE FPL("/a"), false, NULL },
+    {"a2", DRIVE FPL("/a"), false, nullptr},
     // Child of lexicographically last mount point.
-    { "c1", DRIVE FPL("/a/b/c"), false, NULL },
+    {"c1", DRIVE FPL("/a/b/c"), false, nullptr},
     // Parent to all of the mount points.
-    { "root", DRIVE FPL("/"), false, NULL },
+    {"root", DRIVE FPL("/"), false, nullptr},
     // Path contains .. component.
-    { "funky", DRIVE FPL("/tt/fun/../funky"), false, NULL },
+    {"funky", DRIVE FPL("/tt/fun/../funky"), false, nullptr},
     // Windows separators.
 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
-    { "win", DRIVE FPL("\\try\\separators\\win"), true,
-      DRIVE FPL("\\try\\separators\\win") },
-    { "win1", DRIVE FPL("\\try/separators\\win1"), true,
-      DRIVE FPL("\\try/separators\\win1") },
-    { "win2", DRIVE FPL("\\try/separators\\win"), false, NULL },
+    {"win", DRIVE FPL("\\try\\separators\\win"), true,
+     DRIVE FPL("\\try\\separators\\win")},
+    {"win1", DRIVE FPL("\\try/separators\\win1"), true,
+     DRIVE FPL("\\try/separators\\win1")},
+    {"win2", DRIVE FPL("\\try/separators\\win"), false, nullptr},
 #else
-    { "win", DRIVE FPL("\\separators\\win"), false, NULL },
-    { "win1", DRIVE FPL("\\try/separators\\win1"), false, NULL },
+    {"win", DRIVE FPL("\\separators\\win"), false, nullptr},
+    {"win1", DRIVE FPL("\\try/separators\\win1"), false, nullptr},
 #endif
     // Win separators, but relative path.
-    { "win2", DRIVE FPL("try\\separators\\win2"), false, NULL },
+    {"win2", DRIVE FPL("try\\separators\\win2"), false, nullptr},
   };
 
   // Test adding mount points.
@@ -124,7 +124,7 @@
   // Test that final mount point presence state is as expected.
   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
     base::FilePath found_path;
-    EXPECT_EQ(kTestCases[i].registered_path != NULL,
+    EXPECT_EQ(kTestCases[i].registered_path != nullptr,
               mount_points->GetRegisteredPath(kTestCases[i].name, &found_path))
         << "Test case: " << i;
 
diff --git a/storage/browser/fileapi/file_system_backend.h b/storage/browser/fileapi/file_system_backend.h
index cb81fd63..31afaaff 100644
--- a/storage/browser/fileapi/file_system_backend.h
+++ b/storage/browser/fileapi/file_system_backend.h
@@ -83,7 +83,7 @@
   virtual WatcherManager* GetWatcherManager(FileSystemType type) = 0;
 
   // Returns the specialized CopyOrMoveFileValidatorFactory for this backend
-  // and |type|.  If |error_code| is File::FILE_OK and the result is NULL,
+  // and |type|.  If |error_code| is File::FILE_OK and the result is nullptr,
   // then no validator is required.
   virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
       FileSystemType type, base::File::Error* error_code) = 0;
@@ -135,20 +135,20 @@
       FileSystemContext* context) const = 0;
 
   // Returns the specialized FileSystemQuotaUtil for this backend.
-  // This could return NULL if this backend does not support quota.
+  // This could return nullptr if this backend does not support quota.
   virtual FileSystemQuotaUtil* GetQuotaUtil() = 0;
 
-  // Returns the update observer list for |type|. It may return NULL when no
+  // Returns the update observer list for |type|. It may return nullptr when no
   // observers are added.
   virtual const UpdateObserverList* GetUpdateObservers(
       FileSystemType type) const = 0;
 
-  // Returns the change observer list for |type|. It may return NULL when no
+  // Returns the change observer list for |type|. It may return nullptr when no
   // observers are added.
   virtual const ChangeObserverList* GetChangeObservers(
       FileSystemType type) const = 0;
 
-  // Returns the access observer list for |type|. It may return NULL when no
+  // Returns the access observer list for |type|. It may return nullptr when no
   // observers are added.
   virtual const AccessObserverList* GetAccessObservers(
       FileSystemType type) const = 0;
diff --git a/storage/browser/fileapi/file_system_context.cc b/storage/browser/fileapi/file_system_context.cc
index bd051989..dd41383 100644
--- a/storage/browser/fileapi/file_system_context.cc
+++ b/storage/browser/fileapi/file_system_context.cc
@@ -256,7 +256,7 @@
 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
   FileSystemBackend* backend = GetFileSystemBackend(type);
   if (!backend)
-    return NULL;
+    return nullptr;
   return backend->GetQuotaUtil();
 }
 
@@ -264,7 +264,7 @@
     FileSystemType type) const {
   FileSystemBackend* backend = GetFileSystemBackend(type);
   if (!backend)
-    return NULL;
+    return nullptr;
   return backend->GetAsyncFileUtil(type);
 }
 
@@ -275,7 +275,7 @@
   *error_code = base::File::FILE_OK;
   FileSystemBackend* backend = GetFileSystemBackend(type);
   if (!backend)
-    return NULL;
+    return nullptr;
   return backend->GetCopyOrMoveFileValidatorFactory(
       type, error_code);
 }
@@ -286,14 +286,14 @@
   if (found != backend_map_.end())
     return found->second;
   NOTREACHED() << "Unknown filesystem type: " << type;
-  return NULL;
+  return nullptr;
 }
 
 WatcherManager* FileSystemContext::GetWatcherManager(
     FileSystemType type) const {
   FileSystemBackend* backend = GetFileSystemBackend(type);
   if (!backend)
-    return NULL;
+    return nullptr;
   return backend->GetWatcherManager(type);
 }
 
@@ -524,14 +524,14 @@
   if (!url.is_valid()) {
     if (error_code)
       *error_code = base::File::FILE_ERROR_INVALID_URL;
-    return NULL;
+    return nullptr;
   }
 
   FileSystemBackend* backend = GetFileSystemBackend(url.type());
   if (!backend) {
     if (error_code)
       *error_code = base::File::FILE_ERROR_FAILED;
-    return NULL;
+    return nullptr;
   }
 
   base::File::Error fs_error = base::File::FILE_OK;
diff --git a/storage/browser/fileapi/file_system_context.h b/storage/browser/fileapi/file_system_context.h
index 24f576c..9fc8610 100644
--- a/storage/browser/fileapi/file_system_context.h
+++ b/storage/browser/fileapi/file_system_context.h
@@ -108,8 +108,8 @@
   // does).
   //
   // |external_mount_points| contains non-system external mount points available
-  // in the context. If not NULL, it will be used during URL cracking.
-  // |external_mount_points| may be NULL only on platforms different from
+  // in the context. If not nullptr, it will be used during URL cracking.
+  // |external_mount_points| may be nullptr only on platforms different from
   // ChromeOS (i.e. platforms that don't use external_mount_point_provider).
   //
   // |additional_backends| are added to the internal backend map
@@ -134,7 +134,7 @@
   bool DeleteDataForOriginOnFileTaskRunner(const GURL& origin_url);
 
   // Creates a new QuotaReservation for the given |origin_url| and |type|.
-  // Returns NULL if |type| does not support quota or reservation fails.
+  // Returns nullptr if |type| does not support quota or reservation fails.
   // This should be run on |default_file_task_runner_| and the returned value
   // should be destroyed on the runner.
   scoped_refptr<QuotaReservation> CreateQuotaReservationOnFileTaskRunner(
@@ -149,7 +149,7 @@
   void Shutdown();
 
   // Returns a quota util for a given filesystem type.  This may
-  // return NULL if the type does not support the usage tracking or
+  // return nullptr if the type does not support the usage tracking or
   // it is not a quota-managed storage.
   FileSystemQuotaUtil* GetQuotaUtil(FileSystemType type) const;
 
@@ -157,23 +157,23 @@
   AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) const;
 
   // Returns the appropriate CopyOrMoveFileValidatorFactory for the given
-  // |type|.  If |error_code| is File::FILE_OK and the result is NULL,
+  // |type|.  If |error_code| is File::FILE_OK and the result is nullptr,
   // then no validator is required.
   CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory(
       FileSystemType type, base::File::Error* error_code) const;
 
   // Returns the file system backend instance for the given |type|.
-  // This may return NULL if it is given an invalid or unsupported filesystem
+  // This may return nullptr if it is given an invalid or unsupported filesystem
   // type.
   FileSystemBackend* GetFileSystemBackend(
       FileSystemType type) const;
 
   // Returns the watcher manager for the given |type|.
-  // This may return NULL if the type does not support watching.
+  // This may return nullptr if the type does not support watching.
   WatcherManager* GetWatcherManager(FileSystemType type) const;
 
   // Returns true for sandboxed filesystems. Currently this does
-  // the same as GetQuotaUtil(type) != NULL. (In an assumption that
+  // the same as GetQuotaUtil(type) != nullptr. (In an assumption that
   // all sandboxed filesystems must cooperate with QuotaManager so that
   // they can get deleted)
   bool IsSandboxFileSystem(FileSystemType type) const;
diff --git a/storage/browser/fileapi/file_system_context_unittest.cc b/storage/browser/fileapi/file_system_context_unittest.cc
index d1d9059f..213db6e 100644
--- a/storage/browser/fileapi/file_system_context_unittest.cc
+++ b/storage/browser/fileapi/file_system_context_unittest.cc
@@ -101,12 +101,12 @@
   scoped_refptr<MockQuotaManager> mock_quota_manager_;
 };
 
-// It is not valid to pass NULL ExternalMountPoints to FileSystemContext on
+// It is not valid to pass nullptr ExternalMountPoints to FileSystemContext on
 // ChromeOS.
 #if !defined(OS_CHROMEOS)
 TEST_F(FileSystemContextTest, NullExternalMountPoints) {
   scoped_refptr<FileSystemContext> file_system_context(
-      CreateFileSystemContextForTest(NULL));
+      CreateFileSystemContextForTest(nullptr));
 
   // Cracking system external mount and isolated mount points should work.
   std::string isolated_name = "root";
@@ -171,7 +171,7 @@
       CreateFileSystemContextForTest(mount_points.get()));
 
   // Release a MountPoints reference created in the test.
-  mount_points = NULL;
+  mount_points = nullptr;
 
   // FileSystemContext should keep a reference to the |mount_points|, so it
   // should be able to resolve the URL.
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/storage/browser/fileapi/file_system_dir_url_request_job_unittest.cc
index fd57b21..c7dac7e 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job_unittest.cc
+++ b/storage/browser/fileapi/file_system_dir_url_request_job_unittest.cc
@@ -133,7 +133,7 @@
 
     special_storage_policy_ = new MockSpecialStoragePolicy;
     file_system_context_ =
-        CreateFileSystemContextForTesting(NULL, temp_dir_.GetPath());
+        CreateFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
 
     file_system_context_->OpenFileSystem(
         GURL("http://remote/"), storage::kFileSystemTypeTemporary,
@@ -145,8 +145,8 @@
 
   void TearDown() override {
     // NOTE: order matters, request must die before delegate
-    request_.reset(NULL);
-    delegate_.reset(NULL);
+    request_.reset(nullptr);
+    delegate_.reset(nullptr);
   }
 
   void SetUpAutoMountContext(base::FilePath* mnt_point) {
@@ -162,7 +162,8 @@
     handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
 
     file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
-        NULL, std::move(additional_providers), handlers, temp_dir_.GetPath());
+        nullptr, std::move(additional_providers), handlers,
+        temp_dir_.GetPath());
   }
 
   void OnOpenFileSystem(const GURL& root_url,
@@ -225,8 +226,9 @@
   void EnsureFileExists(const base::StringPiece file_name) {
     base::FilePath path = base::FilePath().AppendASCII(file_name);
     std::unique_ptr<FileSystemOperationContext> context(NewOperationContext());
-    ASSERT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(
-        context.get(), CreateURL(path), NULL));
+    ASSERT_EQ(
+        base::File::FILE_OK,
+        file_util()->EnsureFileExists(context.get(), CreateURL(path), nullptr));
   }
 
   void TruncateFile(const base::StringPiece file_name, int64_t length) {
@@ -375,7 +377,7 @@
   CreateDirectory("foo");
 
   scoped_refptr<FileSystemContext> file_system_context =
-      CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.GetPath());
+      CreateIncognitoFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
 
   TestRequestWithContext(CreateFileSystemURL("/"),
                          file_system_context.get());
diff --git a/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc b/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
index 067efc3..444f2aef70 100644
--- a/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
+++ b/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
@@ -44,8 +44,8 @@
                     std::string* data,
                     size_t size,
                     int* result) {
-  ASSERT_TRUE(reader != NULL);
-  ASSERT_TRUE(result != NULL);
+  ASSERT_TRUE(reader != nullptr);
+  ASSERT_TRUE(result != nullptr);
   *result = net::OK;
   net::TestCompletionCallback callback;
   size_t total_bytes_read = 0;
@@ -76,7 +76,7 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
     file_system_context_ =
-        CreateFileSystemContextForTesting(NULL, temp_dir_.GetPath());
+        CreateFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
 
     file_system_context_->OpenFileSystem(
         GURL(kURLOrigin), storage::kFileSystemTypeTemporary,
@@ -156,7 +156,7 @@
 
 TEST_F(FileSystemFileStreamReaderTest, Empty) {
   const char kFileName[] = "empty";
-  WriteFile(kFileName, NULL, 0, NULL);
+  WriteFile(kFileName, nullptr, 0, nullptr);
 
   std::unique_ptr<FileSystemFileStreamReader> reader(
       CreateFileReader(kFileName, 0, base::Time()));
@@ -196,7 +196,7 @@
     result = callback.WaitForResult();
   ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
 
-  // With NULL expected modification time this should work.
+  // With nullptr expected modification time this should work.
   reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
   result = reader->GetLength(callback.callback());
   if (result == net::ERR_IO_PENDING)
@@ -238,7 +238,7 @@
   ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
   ASSERT_EQ(0U, data.size());
 
-  // With NULL expected modification time this should work.
+  // With nullptr expected modification time this should work.
   data.clear();
   reader.reset(CreateFileReader(kTestFileName, 0, base::Time()));
   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
diff --git a/storage/browser/fileapi/file_system_operation.h b/storage/browser/fileapi/file_system_operation.h
index 55a613a..34754e5c 100644
--- a/storage/browser/fileapi/file_system_operation.h
+++ b/storage/browser/fileapi/file_system_operation.h
@@ -15,6 +15,7 @@
 #include "base/files/file_path.h"
 #include "base/process/process.h"
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
+#include "storage/browser/blob/blob_reader.h"
 #include "storage/browser/fileapi/file_system_operation_context.h"
 #include "storage/browser/storage_browser_export.h"
 
@@ -22,10 +23,6 @@
 class Time;
 }
 
-namespace net {
-class URLRequest;
-}
-
 namespace storage {
 class ShareableFileReference;
 }
@@ -106,7 +103,7 @@
   // snapshot file.  It can be set to let the chromium backend take
   // care of the life time of the snapshot file.  Otherwise (if the returned
   // file does not require any handling) the implementation can just
-  // return NULL.  In a more complex case, the implementaiton can manage
+  // return nullptr.  In a more complex case, the implementation can manage
   // the lifetime of the snapshot file on its own (e.g. by its cache system)
   // but also can be notified via the reference when the file becomes no
   // longer necessary in the javascript world.
@@ -321,10 +318,10 @@
   virtual void Remove(const FileSystemURL& path, bool recursive,
                       const StatusCallback& callback) = 0;
 
-  // Writes the data read from |blob_request| using |writer_delegate|.
+  // Writes the data read from |blob_reader| using |writer_delegate|.
   virtual void Write(const FileSystemURL& url,
                      std::unique_ptr<FileWriterDelegate> writer_delegate,
-                     std::unique_ptr<net::URLRequest> blob_request,
+                     std::unique_ptr<BlobReader> blob_reader,
                      const WriteCallback& callback) = 0;
 
   // Truncates a file at |path| to |length|. If |length| is larger than
diff --git a/storage/browser/fileapi/file_system_operation_impl.cc b/storage/browser/fileapi/file_system_operation_impl.cc
index d2d05d2..d43cf07e 100644
--- a/storage/browser/fileapi/file_system_operation_impl.cc
+++ b/storage/browser/fileapi/file_system_operation_impl.cc
@@ -191,12 +191,12 @@
 void FileSystemOperationImpl::Write(
     const FileSystemURL& url,
     std::unique_ptr<FileWriterDelegate> writer_delegate,
-    std::unique_ptr<net::URLRequest> blob_request,
+    std::unique_ptr<BlobReader> blob_reader,
     const WriteCallback& callback) {
   DCHECK(SetPendingOperationType(kOperationWrite));
   file_writer_delegate_ = std::move(writer_delegate);
   file_writer_delegate_->Start(
-      std::move(blob_request),
+      std::move(blob_reader),
       base::Bind(&FileSystemOperationImpl::DidWrite, weak_factory_.GetWeakPtr(),
                  url, callback));
 }
@@ -377,7 +377,7 @@
     std::unique_ptr<FileSystemOperationContext> operation_context)
     : file_system_context_(file_system_context),
       operation_context_(std::move(operation_context)),
-      async_file_util_(NULL),
+      async_file_util_(nullptr),
       pending_operation_(kOperationNone),
       weak_factory_(this) {
   weak_ptr_ = weak_factory_.GetWeakPtr();
diff --git a/storage/browser/fileapi/file_system_operation_impl.h b/storage/browser/fileapi/file_system_operation_impl.h
index d253862..c113e996 100644
--- a/storage/browser/fileapi/file_system_operation_impl.h
+++ b/storage/browser/fileapi/file_system_operation_impl.h
@@ -64,7 +64,7 @@
               const StatusCallback& callback) override;
   void Write(const FileSystemURL& url,
              std::unique_ptr<FileWriterDelegate> writer_delegate,
-             std::unique_ptr<net::URLRequest> blob_request,
+             std::unique_ptr<BlobReader> blob_reader,
              const WriteCallback& callback) override;
   void Truncate(const FileSystemURL& url,
                 int64_t length,
diff --git a/storage/browser/fileapi/file_system_operation_impl_unittest.cc b/storage/browser/fileapi/file_system_operation_impl_unittest.cc
index 7352c9c..293423f 100644
--- a/storage/browser/fileapi/file_system_operation_impl_unittest.cc
+++ b/storage/browser/fileapi/file_system_operation_impl_unittest.cc
@@ -73,7 +73,7 @@
     quota_manager_ =
         new MockQuotaManager(false /* is_incognito */, base_dir,
                              base::ThreadTaskRunnerHandle::Get().get(),
-                             NULL /* special storage policy */);
+                             nullptr /* special storage policy */);
     quota_manager_proxy_ = new MockQuotaManagerProxy(
         quota_manager(), base::ThreadTaskRunnerHandle::Get().get());
     sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
@@ -85,8 +85,8 @@
   void TearDown() override {
     // Let the client go away before dropping a ref of the quota manager proxy.
     quota_manager_proxy()->SimulateQuotaManagerDestroyed();
-    quota_manager_ = NULL;
-    quota_manager_proxy_ = NULL;
+    quota_manager_ = nullptr;
+    quota_manager_proxy_ = nullptr;
     sandbox_file_system_.TearDown();
   }
 
@@ -265,7 +265,7 @@
 
   int64_t ComputePathCost(const FileSystemURL& url) {
     int64_t base_usage;
-    GetUsageAndQuota(&base_usage, NULL);
+    GetUsageAndQuota(&base_usage, nullptr);
 
     AsyncFileTestHelper::CreateFile(
         sandbox_file_system_.file_system_context(), url);
@@ -274,13 +274,13 @@
     change_observer()->ResetCount();
 
     int64_t total_usage;
-    GetUsageAndQuota(&total_usage, NULL);
+    GetUsageAndQuota(&total_usage, nullptr);
     return total_usage - base_usage;
   }
 
   void GrantQuotaForCurrentUsage() {
     int64_t usage;
-    GetUsageAndQuota(&usage, NULL);
+    GetUsageAndQuota(&usage, nullptr);
     quota_manager()->SetQuota(sandbox_file_system_.origin(),
                               sandbox_file_system_.storage_type(),
                               usage);
@@ -288,13 +288,13 @@
 
   int64_t GetUsage() {
     int64_t usage = 0;
-    GetUsageAndQuota(&usage, NULL);
+    GetUsageAndQuota(&usage, nullptr);
     return usage;
   }
 
   void AddQuota(int64_t quota_delta) {
     int64_t quota;
-    GetUsageAndQuota(NULL, &quota);
+    GetUsageAndQuota(nullptr, &quota);
     quota_manager()->SetQuota(sandbox_file_system_.origin(),
                               sandbox_file_system_.storage_type(),
                               quota + quota_delta);
@@ -834,7 +834,7 @@
   FileSystemURL dest_dir(CreateDirectory("dest"));
 
   int64_t before_usage;
-  GetUsageAndQuota(&before_usage, NULL);
+  GetUsageAndQuota(&before_usage, nullptr);
 
   // Check that the file copied and corresponding usage increased.
   EXPECT_EQ(
@@ -844,7 +844,7 @@
   EXPECT_EQ(1, change_observer()->create_file_count());
   EXPECT_TRUE(FileExists("dest/file"));
   int64_t after_usage;
-  GetUsageAndQuota(&after_usage, NULL);
+  GetUsageAndQuota(&after_usage, nullptr);
   EXPECT_GT(after_usage, before_usage);
 
   // Compare contents of src and copied file.
@@ -1206,7 +1206,7 @@
 
   // The FileSystemOpration implementation does not create a
   // shareable file reference.
-  EXPECT_EQ(NULL, shareable_file_ref());
+  EXPECT_EQ(nullptr, shareable_file_ref());
 }
 
 TEST_F(FileSystemOperationImplTest,
diff --git a/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc b/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
index a7c51e0..70b2bfb5 100644
--- a/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
+++ b/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
@@ -73,7 +73,7 @@
     quota_manager_ =
         new MockQuotaManager(false /* is_incognito */, dir_.GetPath(),
                              base::ThreadTaskRunnerHandle::Get().get(),
-                             NULL /* special storage policy */);
+                             nullptr /* special storage policy */);
     virtual_path_ = base::FilePath(FILE_PATH_LITERAL("temporary file"));
 
     file_system_context_ = CreateFileSystemContextForTesting(
@@ -90,8 +90,8 @@
   }
 
   void TearDown() override {
-    quota_manager_ = NULL;
-    file_system_context_ = NULL;
+    quota_manager_ = nullptr;
+    file_system_context_ = nullptr;
     base::RunLoop().RunUntilIdle();
   }
 
@@ -178,9 +178,9 @@
 TEST_F(FileSystemOperationImplWriteTest, TestWriteSuccess) {
   ScopedTextBlob blob(url_request_context(), "blob-id:success",
                       "Hello, world!\n");
-  file_system_context_->operation_runner()->Write(
-      &url_request_context(), URLForPath(virtual_path_),
-      blob.GetBlobDataHandle(), 0, RecordWriteCallback());
+  file_system_context_->operation_runner()->Write(URLForPath(virtual_path_),
+                                                  blob.GetBlobDataHandle(), 0,
+                                                  RecordWriteCallback());
   base::RunLoop().Run();
 
   EXPECT_EQ(14, bytes_written());
@@ -192,9 +192,9 @@
 
 TEST_F(FileSystemOperationImplWriteTest, TestWriteZero) {
   ScopedTextBlob blob(url_request_context(), "blob_id:zero", "");
-  file_system_context_->operation_runner()->Write(
-      &url_request_context(), URLForPath(virtual_path_),
-      blob.GetBlobDataHandle(), 0, RecordWriteCallback());
+  file_system_context_->operation_runner()->Write(URLForPath(virtual_path_),
+                                                  blob.GetBlobDataHandle(), 0,
+                                                  RecordWriteCallback());
   base::RunLoop().Run();
 
   EXPECT_EQ(0, bytes_written());
@@ -204,11 +204,11 @@
   EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
 }
 
-TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) {
+TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlob) {
   std::unique_ptr<storage::BlobDataHandle> null_handle;
-  file_system_context_->operation_runner()->Write(
-      &url_request_context(), URLForPath(virtual_path_), std::move(null_handle),
-      0, RecordWriteCallback());
+  file_system_context_->operation_runner()->Write(URLForPath(virtual_path_),
+                                                  std::move(null_handle), 0,
+                                                  RecordWriteCallback());
   base::RunLoop().Run();
 
   EXPECT_EQ(0, bytes_written());
@@ -222,7 +222,6 @@
   ScopedTextBlob blob(url_request_context(), "blob_id:writeinvalidfile",
                       "It\'ll not be written.");
   file_system_context_->operation_runner()->Write(
-      &url_request_context(),
       URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))),
       blob.GetBlobDataHandle(), 0, RecordWriteCallback());
   base::RunLoop().Run();
@@ -242,9 +241,9 @@
 
   ScopedTextBlob blob(url_request_context(), "blob:writedir",
                       "It\'ll not be written, too.");
-  file_system_context_->operation_runner()->Write(
-      &url_request_context(), URLForPath(virtual_dir_path),
-      blob.GetBlobDataHandle(), 0, RecordWriteCallback());
+  file_system_context_->operation_runner()->Write(URLForPath(virtual_dir_path),
+                                                  blob.GetBlobDataHandle(), 0,
+                                                  RecordWriteCallback());
   base::RunLoop().Run();
 
   EXPECT_EQ(0, bytes_written());
@@ -262,9 +261,9 @@
   ScopedTextBlob blob(url_request_context(), "blob:success", "Hello, world!\n");
   quota_manager_->SetQuota(
       kOrigin, FileSystemTypeToQuotaStorageType(kFileSystemType), 10);
-  file_system_context_->operation_runner()->Write(
-      &url_request_context(), URLForPath(virtual_path_),
-      blob.GetBlobDataHandle(), 0, RecordWriteCallback());
+  file_system_context_->operation_runner()->Write(URLForPath(virtual_path_),
+                                                  blob.GetBlobDataHandle(), 0,
+                                                  RecordWriteCallback());
   base::RunLoop().Run();
 
   EXPECT_EQ(10, bytes_written());
@@ -277,9 +276,9 @@
 TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelSuccessfulWrite) {
   ScopedTextBlob blob(url_request_context(), "blob:success", "Hello, world!\n");
   FileSystemOperationRunner::OperationID id =
-      file_system_context_->operation_runner()->Write(
-          &url_request_context(), URLForPath(virtual_path_),
-          blob.GetBlobDataHandle(), 0, RecordWriteCallback());
+      file_system_context_->operation_runner()->Write(URLForPath(virtual_path_),
+                                                      blob.GetBlobDataHandle(),
+                                                      0, RecordWriteCallback());
   file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback());
   // We use RunAllPendings() instead of Run() here, because we won't dispatch
   // callbacks after Cancel() is issued (so no chance to Quit) nor do we need
@@ -301,7 +300,6 @@
                       "It\'ll not be written.");
   FileSystemOperationRunner::OperationID id =
       file_system_context_->operation_runner()->Write(
-          &url_request_context(),
           URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))),
           blob.GetBlobDataHandle(), 0, RecordWriteCallback());
   file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback());
diff --git a/storage/browser/fileapi/file_system_operation_runner.cc b/storage/browser/fileapi/file_system_operation_runner.cc
index 51c4066..62f62a0 100644
--- a/storage/browser/fileapi/file_system_operation_runner.cc
+++ b/storage/browser/fileapi/file_system_operation_runner.cc
@@ -237,7 +237,6 @@
 }
 
 OperationID FileSystemOperationRunner::Write(
-    const net::URLRequestContext* url_request_context,
     const FileSystemURL& url,
     std::unique_ptr<storage::BlobDataHandle> blob,
     int64_t offset,
@@ -264,12 +263,12 @@
   std::unique_ptr<FileWriterDelegate> writer_delegate(new FileWriterDelegate(
       std::move(writer), url.mount_option().flush_policy()));
 
-  std::unique_ptr<net::URLRequest> blob_request(
-      storage::BlobProtocolHandler::CreateBlobRequest(
-          std::move(blob), url_request_context, writer_delegate.get()));
+  std::unique_ptr<BlobReader> blob_reader;
+  if (blob)
+    blob_reader = blob->CreateReader();
 
   PrepareForWrite(id, url);
-  operation_raw->Write(url, std::move(writer_delegate), std::move(blob_request),
+  operation_raw->Write(url, std::move(writer_delegate), std::move(blob_reader),
                        base::Bind(&FileSystemOperationRunner::DidWrite,
                                   weak_ptr_, id, callback));
   return id;
@@ -377,7 +376,7 @@
   base::AutoReset<bool> beginning(&is_beginning_operation_, true);
   if (!operation_raw) {
     DidCreateSnapshot(id, callback, error, base::File::Info(), base::FilePath(),
-                      NULL);
+                      nullptr);
     return id;
   }
   PrepareForRead(id, url);
diff --git a/storage/browser/fileapi/file_system_operation_runner.h b/storage/browser/fileapi/file_system_operation_runner.h
index f298e11..cf21797 100644
--- a/storage/browser/fileapi/file_system_operation_runner.h
+++ b/storage/browser/fileapi/file_system_operation_runner.h
@@ -21,10 +21,6 @@
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/browser/storage_browser_export.h"
 
-namespace net {
-class URLRequestContext;
-}
-
 namespace storage {
 
 class FileSystemURL;
@@ -114,9 +110,7 @@
                      const StatusCallback& callback);
 
   // Writes contents of |blob_url| to |url| at |offset|.
-  // |url_request_context| is used to read contents in |blob|.
-  OperationID Write(const net::URLRequestContext* url_request_context,
-                    const FileSystemURL& url,
+  OperationID Write(const FileSystemURL& url,
                     std::unique_ptr<storage::BlobDataHandle> blob,
                     int64_t offset,
                     const WriteCallback& callback);
diff --git a/storage/browser/fileapi/file_system_quota_client_unittest.cc b/storage/browser/fileapi/file_system_quota_client_unittest.cc
index 9676d04..a6dc424 100644
--- a/storage/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/storage/browser/fileapi/file_system_quota_client_unittest.cc
@@ -52,7 +52,7 @@
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     file_system_context_ =
-        CreateFileSystemContextForTesting(NULL, data_dir_.GetPath());
+        CreateFileSystemContextForTesting(nullptr, data_dir_.GetPath());
   }
 
   struct TestFile {
@@ -252,7 +252,7 @@
 TEST_F(FileSystemQuotaClientTest, NoFileTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
 
@@ -264,8 +264,8 @@
 TEST_F(FileSystemQuotaClientTest, OneFileTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {false, "foo", 4921, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {false, "foo", 4921, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost = ComputeFilePathsCostForOriginAndType(
@@ -280,9 +280,9 @@
 TEST_F(FileSystemQuotaClientTest, TwoFilesTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {false, "foo", 10310, kDummyURL1, kTemporary},
-    {false, "bar", 41, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {false, "foo", 10310, kDummyURL1, kTemporary},
+      {false, "bar", 41, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost = ComputeFilePathsCostForOriginAndType(
@@ -297,10 +297,10 @@
 TEST_F(FileSystemQuotaClientTest, EmptyFilesTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {false, "foo", 0, kDummyURL1, kTemporary},
-    {false, "bar", 0, kDummyURL1, kTemporary},
-    {false, "baz", 0, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {false, "foo", 0, kDummyURL1, kTemporary},
+      {false, "bar", 0, kDummyURL1, kTemporary},
+      {false, "baz", 0, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost = ComputeFilePathsCostForOriginAndType(
@@ -315,10 +315,10 @@
 TEST_F(FileSystemQuotaClientTest, SubDirectoryTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {true, "dirtest", 0, kDummyURL1, kTemporary},
-    {false, "dirtest/foo", 11921, kDummyURL1, kTemporary},
-    {false, "bar", 4814, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {true, "dirtest", 0, kDummyURL1, kTemporary},
+      {false, "dirtest/foo", 11921, kDummyURL1, kTemporary},
+      {false, "bar", 4814, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost = ComputeFilePathsCostForOriginAndType(
@@ -333,14 +333,14 @@
 TEST_F(FileSystemQuotaClientTest, MultiTypeTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {true, "dirtest", 0, kDummyURL1, kTemporary},
-    {false, "dirtest/foo", 133, kDummyURL1, kTemporary},
-    {false, "bar", 14, kDummyURL1, kTemporary},
-    {true, NULL, 0, kDummyURL1, kPersistent},
-    {true, "dirtest", 0, kDummyURL1, kPersistent},
-    {false, "dirtest/foo", 193, kDummyURL1, kPersistent},
-    {false, "bar", 9, kDummyURL1, kPersistent},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {true, "dirtest", 0, kDummyURL1, kTemporary},
+      {false, "dirtest/foo", 133, kDummyURL1, kTemporary},
+      {false, "bar", 14, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kPersistent},
+      {true, "dirtest", 0, kDummyURL1, kPersistent},
+      {false, "dirtest/foo", 193, kDummyURL1, kPersistent},
+      {false, "bar", 9, kDummyURL1, kPersistent},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost_temporary =
@@ -361,22 +361,22 @@
 TEST_F(FileSystemQuotaClientTest, MultiDomainTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {true, "dir1", 0, kDummyURL1, kTemporary},
-    {false, "dir1/foo", 1331, kDummyURL1, kTemporary},
-    {false, "bar", 134, kDummyURL1, kTemporary},
-    {true, NULL, 0, kDummyURL1, kPersistent},
-    {true, "dir2", 0, kDummyURL1, kPersistent},
-    {false, "dir2/foo", 1903, kDummyURL1, kPersistent},
-    {false, "bar", 19, kDummyURL1, kPersistent},
-    {true, NULL, 0, kDummyURL2, kTemporary},
-    {true, "dom", 0, kDummyURL2, kTemporary},
-    {false, "dom/fan", 1319, kDummyURL2, kTemporary},
-    {false, "bar", 113, kDummyURL2, kTemporary},
-    {true, NULL, 0, kDummyURL2, kPersistent},
-    {true, "dom", 0, kDummyURL2, kPersistent},
-    {false, "dom/fan", 2013, kDummyURL2, kPersistent},
-    {false, "baz", 18, kDummyURL2, kPersistent},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {true, "dir1", 0, kDummyURL1, kTemporary},
+      {false, "dir1/foo", 1331, kDummyURL1, kTemporary},
+      {false, "bar", 134, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kPersistent},
+      {true, "dir2", 0, kDummyURL1, kPersistent},
+      {false, "dir2/foo", 1903, kDummyURL1, kPersistent},
+      {false, "bar", 19, kDummyURL1, kPersistent},
+      {true, nullptr, 0, kDummyURL2, kTemporary},
+      {true, "dom", 0, kDummyURL2, kTemporary},
+      {false, "dom/fan", 1319, kDummyURL2, kTemporary},
+      {false, "bar", 113, kDummyURL2, kTemporary},
+      {true, nullptr, 0, kDummyURL2, kPersistent},
+      {true, "dom", 0, kDummyURL2, kPersistent},
+      {false, "dom/fan", 2013, kDummyURL2, kPersistent},
+      {false, "baz", 18, kDummyURL2, kPersistent},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost_temporary1 =
@@ -407,9 +407,9 @@
 TEST_F(FileSystemQuotaClientTest, GetUsage_MultipleTasks) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {false, "foo",   11, kDummyURL1, kTemporary},
-    {false, "bar",   22, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {false, "foo", 11, kDummyURL1, kTemporary},
+      {false, "bar", 22, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost = ComputeFilePathsCostForOriginAndType(
@@ -437,9 +437,9 @@
 TEST_F(FileSystemQuotaClientTest, GetOriginsForType) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {true, NULL, 0, kDummyURL2, kTemporary},
-    {true, NULL, 0, kDummyURL3, kPersistent},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL2, kTemporary},
+      {true, nullptr, 0, kDummyURL3, kPersistent},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
 
@@ -462,11 +462,11 @@
   const char* kURL4 = "http://foo2.com/";
   const char* kURL5 = "http://foo.com:2/";
   const TestFile kFiles[] = {
-    {true, NULL, 0, kURL1, kTemporary},
-    {true, NULL, 0, kURL2, kTemporary},
-    {true, NULL, 0, kURL3, kTemporary},
-    {true, NULL, 0, kURL4, kTemporary},
-    {true, NULL, 0, kURL5, kPersistent},
+      {true, nullptr, 0, kURL1, kTemporary},
+      {true, nullptr, 0, kURL2, kTemporary},
+      {true, nullptr, 0, kURL3, kTemporary},
+      {true, nullptr, 0, kURL4, kTemporary},
+      {true, nullptr, 0, kURL5, kPersistent},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
 
@@ -485,8 +485,8 @@
 TEST_F(FileSystemQuotaClientTest, IncognitoTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(true));
   const TestFile kFiles[] = {
-    {true, NULL, 0, kDummyURL1, kTemporary},
-    {false, "foo", 10, kDummyURL1, kTemporary},
+      {true, nullptr, 0, kDummyURL1, kTemporary},
+      {false, "foo", 10, kDummyURL1, kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
 
@@ -505,20 +505,20 @@
 TEST_F(FileSystemQuotaClientTest, DeleteOriginTest) {
   std::unique_ptr<FileSystemQuotaClient> quota_client(NewQuotaClient(false));
   const TestFile kFiles[] = {
-    {true, NULL,  0, "http://foo.com/",  kTemporary},
-    {false, "a",  1, "http://foo.com/",  kTemporary},
-    {true, NULL,  0, "https://foo.com/", kTemporary},
-    {false, "b",  2, "https://foo.com/", kTemporary},
-    {true, NULL,  0, "http://foo.com/",  kPersistent},
-    {false, "c",  4, "http://foo.com/",  kPersistent},
-    {true, NULL,  0, "http://bar.com/",  kTemporary},
-    {false, "d",  8, "http://bar.com/",  kTemporary},
-    {true, NULL,  0, "http://bar.com/",  kPersistent},
-    {false, "e", 16, "http://bar.com/",  kPersistent},
-    {true, NULL,  0, "https://bar.com/", kPersistent},
-    {false, "f", 32, "https://bar.com/", kPersistent},
-    {true, NULL,  0, "https://bar.com/", kTemporary},
-    {false, "g", 64, "https://bar.com/", kTemporary},
+      {true, nullptr, 0, "http://foo.com/", kTemporary},
+      {false, "a", 1, "http://foo.com/", kTemporary},
+      {true, nullptr, 0, "https://foo.com/", kTemporary},
+      {false, "b", 2, "https://foo.com/", kTemporary},
+      {true, nullptr, 0, "http://foo.com/", kPersistent},
+      {false, "c", 4, "http://foo.com/", kPersistent},
+      {true, nullptr, 0, "http://bar.com/", kTemporary},
+      {false, "d", 8, "http://bar.com/", kTemporary},
+      {true, nullptr, 0, "http://bar.com/", kPersistent},
+      {false, "e", 16, "http://bar.com/", kPersistent},
+      {true, nullptr, 0, "https://bar.com/", kPersistent},
+      {false, "f", 32, "https://bar.com/", kPersistent},
+      {true, nullptr, 0, "https://bar.com/", kTemporary},
+      {false, "g", 64, "https://bar.com/", kTemporary},
   };
   InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
   const int64_t file_paths_cost_temporary_foo_https =
diff --git a/storage/browser/fileapi/file_system_url_request_job.cc b/storage/browser/fileapi/file_system_url_request_job.cc
index a271317..152d67f 100644
--- a/storage/browser/fileapi/file_system_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_url_request_job.cc
@@ -86,7 +86,7 @@
   DCHECK_NE(dest_size, 0);
   DCHECK_GE(remaining_bytes_, 0);
 
-  if (reader_.get() == NULL)
+  if (reader_.get() == nullptr)
     return net::ERR_FAILED;
 
   if (remaining_bytes_ < dest_size)
diff --git a/storage/browser/fileapi/file_system_url_request_job_unittest.cc b/storage/browser/fileapi/file_system_url_request_job_unittest.cc
index 2caef9d..4e64cef 100644
--- a/storage/browser/fileapi/file_system_url_request_job_unittest.cc
+++ b/storage/browser/fileapi/file_system_url_request_job_unittest.cc
@@ -139,7 +139,7 @@
     // We use the main thread so that we can get the root path synchronously.
     // TODO(adamk): Run this on the FILE thread we've created as well.
     file_system_context_ =
-        CreateFileSystemContextForTesting(NULL, temp_dir_.GetPath());
+        CreateFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
 
     file_system_context_->OpenFileSystem(
         GURL("http://remote/"), storage::kFileSystemTypeTemporary,
@@ -168,7 +168,8 @@
     handlers.push_back(base::BindRepeating(&TestAutoMountForURLRequest));
 
     file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
-        NULL, std::move(additional_providers), handlers, temp_dir_.GetPath());
+        nullptr, std::move(additional_providers), handlers,
+        temp_dir_.GetPath());
 
     ASSERT_EQ(static_cast<int>(sizeof(kTestFileData)) - 1,
               base::WriteFile(mnt_point.AppendASCII("foo"), kTestFileData,
@@ -204,12 +205,12 @@
   }
 
   void TestRequest(const GURL& url) {
-    TestRequestHelper(url, NULL, true, file_system_context_.get());
+    TestRequestHelper(url, nullptr, true, file_system_context_.get());
   }
 
   void TestRequestWithContext(const GURL& url,
                               FileSystemContext* file_system_context) {
-    TestRequestHelper(url, NULL, true, file_system_context);
+    TestRequestHelper(url, nullptr, true, file_system_context);
   }
 
   void TestRequestWithHeaders(const GURL& url,
@@ -218,7 +219,7 @@
   }
 
   void TestRequestNoRun(const GURL& url) {
-    TestRequestHelper(url, NULL, false, file_system_context_.get());
+    TestRequestHelper(url, nullptr, false, file_system_context_.get());
   }
 
   void CreateDirectory(const base::StringPiece& dir_name) {
@@ -419,7 +420,7 @@
 
   // Creates a new filesystem context for incognito mode.
   scoped_refptr<FileSystemContext> file_system_context =
-      CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.GetPath());
+      CreateIncognitoFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
 
   // The request should return NOT_FOUND error if it's in incognito mode.
   TestRequestWithContext(CreateFileSystemURL("file"),
diff --git a/storage/browser/fileapi/file_writer_delegate.cc b/storage/browser/fileapi/file_writer_delegate.cc
index 9237aeb..7a64139b 100644
--- a/storage/browser/fileapi/file_writer_delegate.cc
+++ b/storage/browser/fileapi/file_writer_delegate.cc
@@ -40,16 +40,35 @@
 
 FileWriterDelegate::~FileWriterDelegate() = default;
 
-void FileWriterDelegate::Start(std::unique_ptr<net::URLRequest> request,
+void FileWriterDelegate::Start(std::unique_ptr<BlobReader> blob_reader,
                                const DelegateWriteCallback& write_callback) {
   write_callback_ = write_callback;
-  request_ = std::move(request);
-  request_->Start();
+
+  if (!blob_reader) {
+    OnReadError(base::File::FILE_ERROR_FAILED);
+    return;
+  }
+
+  blob_reader_ = std::move(blob_reader);
+  BlobReader::Status status = blob_reader_->CalculateSize(base::BindOnce(
+      &FileWriterDelegate::OnDidCalculateSize, weak_factory_.GetWeakPtr()));
+  switch (status) {
+    case BlobReader::Status::NET_ERROR:
+      OnDidCalculateSize(blob_reader_->net_error());
+      return;
+    case BlobReader::Status::DONE:
+      OnDidCalculateSize(net::OK);
+      return;
+    case BlobReader::Status::IO_PENDING:
+      // Do nothing.
+      return;
+  }
+  NOTREACHED();
 }
 
 void FileWriterDelegate::Cancel() {
-  // Destroy the request and invalidate weak ptrs to prevent pending callbacks.
-  request_.reset();
+  // Destroy the reader and invalidate weak ptrs to prevent pending callbacks.
+  blob_reader_ = nullptr;
   weak_factory_.InvalidateWeakPtrs();
 
   const int status = file_stream_writer_->Cancel(
@@ -63,53 +82,21 @@
   }
 }
 
-void FileWriterDelegate::OnReceivedRedirect(
-    net::URLRequest* request,
-    const net::RedirectInfo& redirect_info,
-    bool* defer_redirect) {
-  NOTREACHED();
-  OnReadError(base::File::FILE_ERROR_SECURITY);
-}
-
-void FileWriterDelegate::OnAuthRequired(net::URLRequest* request,
-                                        net::AuthChallengeInfo* auth_info) {
-  NOTREACHED();
-  OnReadError(base::File::FILE_ERROR_SECURITY);
-}
-
-void FileWriterDelegate::OnCertificateRequested(
-    net::URLRequest* request,
-    net::SSLCertRequestInfo* cert_request_info) {
-  NOTREACHED();
-  OnReadError(base::File::FILE_ERROR_SECURITY);
-}
-
-void FileWriterDelegate::OnSSLCertificateError(net::URLRequest* request,
-                                               const net::SSLInfo& ssl_info,
-                                               bool fatal) {
-  NOTREACHED();
-  OnReadError(base::File::FILE_ERROR_SECURITY);
-}
-
-void FileWriterDelegate::OnResponseStarted(net::URLRequest* request,
-                                           int net_error) {
+void FileWriterDelegate::OnDidCalculateSize(int net_error) {
   DCHECK_NE(net::ERR_IO_PENDING, net_error);
-  DCHECK_EQ(request_.get(), request);
 
-  if (net_error != net::OK || request->GetResponseCode() != 200) {
-    OnReadError(base::File::FILE_ERROR_FAILED);
+  if (net_error != net::OK) {
+    OnReadError(NetErrorToFileError(net_error));
     return;
   }
   Read();
 }
 
-void FileWriterDelegate::OnReadCompleted(net::URLRequest* request,
-                                         int bytes_read) {
+void FileWriterDelegate::OnReadCompleted(int bytes_read) {
   DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
-  DCHECK_EQ(request_.get(), request);
 
   if (bytes_read < 0) {
-    OnReadError(base::File::FILE_ERROR_FAILED);
+    OnReadError(NetErrorToFileError(bytes_read));
     return;
   }
   OnDataReceived(bytes_read);
@@ -117,17 +104,24 @@
 
 void FileWriterDelegate::Read() {
   bytes_written_ = 0;
-  bytes_read_ = request_->Read(io_buffer_.get(), io_buffer_->size());
-  if (bytes_read_ == net::ERR_IO_PENDING)
-    return;
-
-  if (bytes_read_ >= 0) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&FileWriterDelegate::OnDataReceived,
-                                  weak_factory_.GetWeakPtr(), bytes_read_));
-  } else {
-    OnReadError(base::File::FILE_ERROR_FAILED);
+  BlobReader::Status status =
+      blob_reader_->Read(io_buffer_.get(), io_buffer_->size(), &bytes_read_,
+                         base::BindOnce(&FileWriterDelegate::OnReadCompleted,
+                                        weak_factory_.GetWeakPtr()));
+  switch (status) {
+    case BlobReader::Status::NET_ERROR:
+      OnReadCompleted(blob_reader_->net_error());
+      return;
+    case BlobReader::Status::DONE:
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(&FileWriterDelegate::OnReadCompleted,
+                                    weak_factory_.GetWeakPtr(), bytes_read_));
+      return;
+    case BlobReader::Status::IO_PENDING:
+      // Do nothing.
+      return;
   }
+  NOTREACHED();
 }
 
 void FileWriterDelegate::OnDataReceived(int bytes_read) {
@@ -195,8 +189,8 @@
     return;
   }
 
-  // Destroy the request and invalidate weak ptrs to prevent pending callbacks.
-  request_.reset();
+  // Destroy the reader and invalidate weak ptrs to prevent pending callbacks.
+  blob_reader_.reset();
   weak_factory_.InvalidateWeakPtrs();
 
   if (writing_started_)
@@ -206,8 +200,8 @@
 }
 
 void FileWriterDelegate::OnWriteError(base::File::Error error) {
-  // Destroy the request and invalidate weak ptrs to prevent pending callbacks.
-  request_.reset();
+  // Destroy the reader and invalidate weak ptrs to prevent pending callbacks.
+  blob_reader_.reset();
   weak_factory_.InvalidateWeakPtrs();
 
   // Errors when writing are not recoverable, so don't bother flushing.
diff --git a/storage/browser/fileapi/file_writer_delegate.h b/storage/browser/fileapi/file_writer_delegate.h
index ed134c18..3671c3b 100644
--- a/storage/browser/fileapi/file_writer_delegate.h
+++ b/storage/browser/fileapi/file_writer_delegate.h
@@ -16,7 +16,7 @@
 #include "base/time/time.h"
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
-#include "net/url_request/url_request.h"
+#include "storage/browser/blob/blob_reader.h"
 #include "storage/browser/storage_browser_export.h"
 
 namespace storage {
@@ -24,7 +24,7 @@
 class FileStreamWriter;
 enum class FlushPolicy;
 
-class STORAGE_EXPORT FileWriterDelegate : public net::URLRequest::Delegate {
+class STORAGE_EXPORT FileWriterDelegate {
  public:
   enum WriteProgressStatus {
     SUCCESS_IO_PENDING,
@@ -40,9 +40,9 @@
 
   FileWriterDelegate(std::unique_ptr<FileStreamWriter> file_writer,
                      FlushPolicy flush_policy);
-  ~FileWriterDelegate() override;
+  virtual ~FileWriterDelegate();
 
-  void Start(std::unique_ptr<net::URLRequest> request,
+  void Start(std::unique_ptr<BlobReader> blob_reader,
              const DelegateWriteCallback& write_callback);
 
   // Cancels the current write operation.  This will synchronously or
@@ -50,29 +50,15 @@
   // deleting this).
   void Cancel();
 
-  void OnReceivedRedirect(net::URLRequest* request,
-                          const net::RedirectInfo& redirect_info,
-                          bool* defer_redirect) override;
-  void OnAuthRequired(net::URLRequest* request,
-                      net::AuthChallengeInfo* auth_info) override;
-  void OnCertificateRequested(
-      net::URLRequest* request,
-      net::SSLCertRequestInfo* cert_request_info) override;
-  void OnSSLCertificateError(net::URLRequest* request,
-                             const net::SSLInfo& ssl_info,
-                             bool fatal) override;
-  void OnResponseStarted(net::URLRequest* request, int net_error) override;
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-
  protected:
   // Virtual for tests.
   virtual void OnDataReceived(int bytes_read);
 
  private:
-  void OnGetFileInfoAndStartRequest(std::unique_ptr<net::URLRequest> request,
-                                    base::File::Error error,
-                                    const base::File::Info& file_info);
+  void OnDidCalculateSize(int net_error);
+
   void Read();
+  void OnReadCompleted(int bytes_read);
   void Write();
   void OnDataWritten(int write_response);
   void OnReadError(base::File::Error error);
@@ -101,7 +87,7 @@
   base::File::Error saved_read_error_ = base::File::FILE_OK;
   scoped_refptr<net::IOBufferWithSize> io_buffer_;
   scoped_refptr<net::DrainableIOBuffer> cursor_;
-  std::unique_ptr<net::URLRequest> request_;
+  std::unique_ptr<BlobReader> blob_reader_;
 
   base::WeakPtrFactory<FileWriterDelegate> weak_factory_;
 
diff --git a/storage/browser/fileapi/file_writer_delegate_unittest.cc b/storage/browser/fileapi/file_writer_delegate_unittest.cc
index 2839396..eb78e5f 100644
--- a/storage/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/storage/browser/fileapi/file_writer_delegate_unittest.cc
@@ -14,9 +14,9 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/request_priority.h"
@@ -27,6 +27,8 @@
 #include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_job_factory.h"
 #include "net/url_request/url_request_status.h"
+#include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_quota_util.h"
 #include "storage/browser/fileapi/file_writer_delegate.h"
@@ -92,7 +94,9 @@
 
 class FileWriterDelegateTest : public PlatformTest {
  public:
-  FileWriterDelegateTest() = default;
+  FileWriterDelegateTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
 
  protected:
   void SetUp() override;
@@ -146,157 +150,57 @@
     return base::BindRepeating(&Result::DidWrite, base::Unretained(result));
   }
 
-  // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
-  // and creates a new FileWriterDelegate for the file.
+  // Creates and sets up a FileWriterDelegate for writing the given
+  // |blob_content|, and creates a new FileWriterDelegate for the file.
   void PrepareForWrite(const char* test_file_path,
-                       const GURL& blob_url,
                        int64_t offset,
                        int64_t allowed_growth) {
     file_writer_delegate_ =
         CreateWriterDelegate(test_file_path, offset, allowed_growth);
-    request_ = empty_context_.CreateRequest(blob_url, net::DEFAULT_PRIORITY,
-                                            file_writer_delegate_.get(),
-                                            TRAFFIC_ANNOTATION_FOR_TESTS);
+  }
+
+  std::unique_ptr<storage::BlobDataHandle> CreateBlob(
+      const std::string& contents) {
+    auto builder = std::make_unique<storage::BlobDataBuilder>("blob-uuid");
+    builder->AppendData(contents);
+    return blob_context_->AddFinishedBlob(std::move(builder));
   }
 
   // This should be alive until the very end of this instance.
-  base::MessageLoopForIO loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   scoped_refptr<storage::FileSystemContext> file_system_context_;
+  std::unique_ptr<storage::BlobStorageContext> blob_context_;
 
-  net::URLRequestContext empty_context_;
   std::unique_ptr<FileWriterDelegate> file_writer_delegate_;
-  std::unique_ptr<net::URLRequest> request_;
-  std::unique_ptr<BlobURLRequestJobFactory> job_factory_;
 
   base::ScopedTempDir dir_;
-
-  static const char* content_;
 };
 
-const char* FileWriterDelegateTest::content_ = NULL;
-
-namespace {
-
-static std::string g_content;
-
-class FileWriterDelegateTestJob : public net::URLRequestJob {
- public:
-  FileWriterDelegateTestJob(net::URLRequest* request,
-                            net::NetworkDelegate* network_delegate,
-                            const std::string& content)
-      : net::URLRequestJob(request, network_delegate),
-        content_(content),
-        remaining_bytes_(content.length()),
-        cursor_(0),
-        weak_factory_(this) {}
-
-  void Start() override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&FileWriterDelegateTestJob::NotifyHeadersComplete,
-                       weak_factory_.GetWeakPtr()));
-  }
-
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
-    if (remaining_bytes_ < buf_size)
-      buf_size = remaining_bytes_;
-
-    for (int i = 0; i < buf_size; ++i)
-      buf->data()[i] = content_[cursor_++];
-    remaining_bytes_ -= buf_size;
-
-    return buf_size;
-  }
-
-  void GetResponseInfo(net::HttpResponseInfo* info) override {
-    const char kStatus[] = "HTTP/1.1 200 OK\0";
-    const size_t kStatusLen = arraysize(kStatus);
-
-    info->headers =
-        new net::HttpResponseHeaders(std::string(kStatus, kStatusLen));
-  }
-
- protected:
-  ~FileWriterDelegateTestJob() override = default;
-
- private:
-  std::string content_;
-  int remaining_bytes_;
-  int cursor_;
-
-  base::WeakPtrFactory<FileWriterDelegateTestJob> weak_factory_;
-};
-
-class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
- public:
-  explicit BlobURLRequestJobFactory(const char** content_data)
-      : content_data_(content_data) {
-  }
-
-  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-      const std::string& scheme,
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return new FileWriterDelegateTestJob(request, network_delegate,
-                                         *content_data_);
-  }
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override {
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
-  bool IsHandledProtocol(const std::string& scheme) const override {
-    return scheme == "blob";
-  }
-
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return true;
-  }
-
- private:
-  const char** content_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(BlobURLRequestJobFactory);
-};
-
-}  // namespace (anonymous)
-
 void FileWriterDelegateTest::SetUp() {
   ASSERT_TRUE(dir_.CreateUniqueTempDir());
 
   file_system_context_ =
-      CreateFileSystemContextForTesting(NULL, dir_.GetPath());
+      CreateFileSystemContextForTesting(nullptr, dir_.GetPath());
   ASSERT_EQ(base::File::FILE_OK,
             AsyncFileTestHelper::CreateFile(file_system_context_.get(),
                                             GetFileSystemURL("test")));
-  job_factory_ = std::make_unique<BlobURLRequestJobFactory>(&content_);
-  empty_context_.set_job_factory(job_factory_.get());
+  blob_context_ = std::make_unique<storage::BlobStorageContext>();
 }
 
 void FileWriterDelegateTest::TearDown() {
-  file_system_context_ = NULL;
+  file_system_context_ = nullptr;
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
-  const GURL kBlobURL("blob:nolimit");
-  content_ = kData;
+  auto blob = CreateBlob(kData);
 
-  PrepareForWrite("test", kBlobURL, 0, std::numeric_limits<int64_t>::max());
+  PrepareForWrite("test", 0, std::numeric_limits<int64_t>::max());
 
   Result result;
   ASSERT_EQ(0, usage());
-  file_writer_delegate_->Start(std::move(request_), GetWriteCallback(&result));
+  file_writer_delegate_->Start(blob->CreateReader(), GetWriteCallback(&result));
   base::RunLoop().Run();
 
   ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
@@ -309,14 +213,13 @@
 }
 
 TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
-  const GURL kBlobURL("blob:just");
-  content_ = kData;
+  auto blob = CreateBlob(kData);
   const int64_t kAllowedGrowth = kDataSize;
-  PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+  PrepareForWrite("test", 0, kAllowedGrowth);
 
   Result result;
   ASSERT_EQ(0, usage());
-  file_writer_delegate_->Start(std::move(request_), GetWriteCallback(&result));
+  file_writer_delegate_->Start(blob->CreateReader(), GetWriteCallback(&result));
   base::RunLoop().Run();
   ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
   file_writer_delegate_.reset();
@@ -329,14 +232,13 @@
 }
 
 TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
-  const GURL kBlobURL("blob:failure");
-  content_ = kData;
+  auto blob = CreateBlob(kData);
   const int64_t kAllowedGrowth = kDataSize - 1;
-  PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+  PrepareForWrite("test", 0, kAllowedGrowth);
 
   Result result;
   ASSERT_EQ(0, usage());
-  file_writer_delegate_->Start(std::move(request_), GetWriteCallback(&result));
+  file_writer_delegate_->Start(blob->CreateReader(), GetWriteCallback(&result));
   base::RunLoop().Run();
   ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
   file_writer_delegate_.reset();
@@ -350,14 +252,13 @@
 }
 
 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
-  const GURL kBlobURL("blob:zero");
-  content_ = "";
+  auto blob = CreateBlob("");
   int64_t kAllowedGrowth = 0;
-  PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
+  PrepareForWrite("test", 0, kAllowedGrowth);
 
   Result result;
   ASSERT_EQ(0, usage());
-  file_writer_delegate_->Start(std::move(request_), GetWriteCallback(&result));
+  file_writer_delegate_->Start(blob->CreateReader(), GetWriteCallback(&result));
   base::RunLoop().Run();
   ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
   file_writer_delegate_.reset();
@@ -372,29 +273,24 @@
 
 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
   std::unique_ptr<FileWriterDelegate> file_writer_delegate2;
-  std::unique_ptr<net::URLRequest> request2;
 
   ASSERT_EQ(base::File::FILE_OK,
             AsyncFileTestHelper::CreateFile(file_system_context_.get(),
                                             GetFileSystemURL("test2")));
 
-  const GURL kBlobURL("blob:nolimitconcurrent");
-  const GURL kBlobURL2("blob:nolimitconcurrent2");
-  content_ = kData;
+  auto blob = CreateBlob(kData);
 
-  PrepareForWrite("test", kBlobURL, 0, std::numeric_limits<int64_t>::max());
+  PrepareForWrite("test", 0, std::numeric_limits<int64_t>::max());
 
   // Create another FileWriterDelegate for concurrent write.
   file_writer_delegate2 =
       CreateWriterDelegate("test2", 0, std::numeric_limits<int64_t>::max());
-  request2 = empty_context_.CreateRequest(kBlobURL2, net::DEFAULT_PRIORITY,
-                                          file_writer_delegate2.get(),
-                                          TRAFFIC_ANNOTATION_FOR_TESTS);
 
   Result result, result2;
   ASSERT_EQ(0, usage());
-  file_writer_delegate_->Start(std::move(request_), GetWriteCallback(&result));
-  file_writer_delegate2->Start(std::move(request2), GetWriteCallback(&result2));
+  file_writer_delegate_->Start(blob->CreateReader(), GetWriteCallback(&result));
+  file_writer_delegate2->Start(blob->CreateReader(),
+                               GetWriteCallback(&result2));
   base::RunLoop().Run();
   if (result.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING ||
       result2.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING)
@@ -415,19 +311,18 @@
 }
 
 TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
-  const GURL kBlobURL("blob:failure-with-updated-quota");
-  content_ = kData;
+  auto blob = CreateBlob(kData);
 
   // Writing kDataSize (=45) bytes data while allowed_growth is 100.
   int64_t offset = 0;
   int64_t allowed_growth = 100;
   ASSERT_LT(kDataSize, allowed_growth);
-  PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+  PrepareForWrite("test", offset, allowed_growth);
 
   {
     Result result;
     ASSERT_EQ(0, usage());
-    file_writer_delegate_->Start(std::move(request_),
+    file_writer_delegate_->Start(blob->CreateReader(),
                                  GetWriteCallback(&result));
     base::RunLoop().Run();
     ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
@@ -442,11 +337,11 @@
   // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
   offset = 0;
   allowed_growth = 20;
-  PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+  PrepareForWrite("test", offset, allowed_growth);
 
   {
     Result result;
-    file_writer_delegate_->Start(std::move(request_),
+    file_writer_delegate_->Start(blob->CreateReader(),
                                  GetWriteCallback(&result));
     base::RunLoop().Run();
     EXPECT_EQ(kDataSize, usage());
@@ -460,11 +355,11 @@
   // allowed_growth is 55.
   offset = 25;
   allowed_growth = 55;
-  PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+  PrepareForWrite("test", offset, allowed_growth);
 
   {
     Result result;
-    file_writer_delegate_->Start(std::move(request_),
+    file_writer_delegate_->Start(blob->CreateReader(),
                                  GetWriteCallback(&result));
     base::RunLoop().Run();
     ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
@@ -479,12 +374,12 @@
   // Trying to overwrite 45 bytes data while allowed_growth is -20.
   offset = 0;
   allowed_growth = -20;
-  PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+  PrepareForWrite("test", offset, allowed_growth);
   int64_t pre_write_usage = GetFileSizeOnDisk("test");
 
   {
     Result result;
-    file_writer_delegate_->Start(std::move(request_),
+    file_writer_delegate_->Start(blob->CreateReader(),
                                  GetWriteCallback(&result));
     base::RunLoop().Run();
     ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
@@ -501,11 +396,11 @@
   const int kOverlap = 20;
   offset = pre_write_usage - kOverlap;
   allowed_growth = 10;
-  PrepareForWrite("test", kBlobURL, offset, allowed_growth);
+  PrepareForWrite("test", offset, allowed_growth);
 
   {
     Result result;
-    file_writer_delegate_->Start(std::move(request_),
+    file_writer_delegate_->Start(blob->CreateReader(),
                                  GetWriteCallback(&result));
     base::RunLoop().Run();
     ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
@@ -518,53 +413,4 @@
   }
 }
 
-class InterruptedFileWriterDelegate : public FileWriterDelegate {
- public:
-  InterruptedFileWriterDelegate(
-      std::unique_ptr<storage::FileStreamWriter> file_writer,
-      storage::FlushPolicy flush_policy)
-      : FileWriterDelegate(std::move(file_writer), flush_policy) {}
-  ~InterruptedFileWriterDelegate() override = default;
-
-  void OnDataReceived(int bytes_read) override {
-    // The base class will respond to OnDataReceived by performing an
-    // asynchronous write. Schedule a task now that will execute before the
-    // write completes which terminates the URLRequestJob.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(IgnoreResult(&net::URLRequest::Cancel),
-                                  base::Unretained(request_)));
-    FileWriterDelegate::OnDataReceived(bytes_read);
-  }
-
-  void set_request(net::URLRequest* request) { request_ = request; }
-
- private:
-  // The request is owned by the base class as a private member.
-  net::URLRequest* request_ = nullptr;
-};
-
-TEST_F(FileWriterDelegateTest, ReadFailureDuringAsyncWrite) {
-  const GURL kBlobURL("blob:async-fail");
-  content_ = kData;
-
-  auto writer = CreateWriter("test", 0, std::numeric_limits<int64_t>::max());
-  auto file_writer_delegate = std::make_unique<InterruptedFileWriterDelegate>(
-      std::move(writer), storage::FlushPolicy::FLUSH_ON_COMPLETION);
-  auto request = empty_context_.CreateRequest(kBlobURL, net::DEFAULT_PRIORITY,
-                                              file_writer_delegate.get(),
-                                              TRAFFIC_ANNOTATION_FOR_TESTS);
-  file_writer_delegate->set_request(request.get());
-
-  Result result;
-  file_writer_delegate->Start(std::move(request), GetWriteCallback(&result));
-  base::RunLoop().Run();
-
-  ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
-  file_writer_delegate_.reset();
-
-  // The write should still have flushed.
-  ASSERT_EQ(kDataSize, usage());
-  EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
-}
-
 }  // namespace content
diff --git a/storage/browser/fileapi/isolated_context_unittest.cc b/storage/browser/fileapi/isolated_context_unittest.cc
index ec8eab8..990a67c4 100644
--- a/storage/browser/fileapi/isolated_context_unittest.cc
+++ b/storage/browser/fileapi/isolated_context_unittest.cc
@@ -127,7 +127,7 @@
 
   std::string id2 = isolated_context()->RegisterFileSystemForPath(
       kFileSystemTypeNativeLocal, std::string(),
-      base::FilePath(DRIVE FPL("/foo")), NULL);
+      base::FilePath(DRIVE FPL("/foo")), nullptr);
 
   // Make sure the GetDraggedFileInfo returns false for both ones.
   ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id2, &toplevels));
@@ -139,11 +139,11 @@
 
   // Try registering three more file systems for the same path as id2.
   std::string id3 = isolated_context()->RegisterFileSystemForPath(
-      kFileSystemTypeNativeLocal, std::string(), path, NULL);
+      kFileSystemTypeNativeLocal, std::string(), path, nullptr);
   std::string id4 = isolated_context()->RegisterFileSystemForPath(
-      kFileSystemTypeNativeLocal, std::string(), path, NULL);
+      kFileSystemTypeNativeLocal, std::string(), path, nullptr);
   std::string id5 = isolated_context()->RegisterFileSystemForPath(
-      kFileSystemTypeNativeLocal, std::string(), path, NULL);
+      kFileSystemTypeNativeLocal, std::string(), path, nullptr);
 
   // Remove file system for id4.
   isolated_context()->AddReference(id4);
@@ -283,7 +283,8 @@
   // that has no corresponding platform directory.
   base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_);
   ASSERT_TRUE(isolated_context()->CrackVirtualPath(
-      virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option));
+      virtual_path, &cracked_id, nullptr, nullptr, &cracked_path,
+      &cracked_option));
   ASSERT_EQ(FPL(""), cracked_path.value());
   ASSERT_EQ(id_, cracked_id);
 
@@ -292,7 +293,8 @@
   virtual_path = isolated_context()->CreateVirtualRootPath(
       id_).AppendASCII("foo");
   ASSERT_FALSE(isolated_context()->CrackVirtualPath(
-      virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option));
+      virtual_path, &cracked_id, nullptr, nullptr, &cracked_path,
+      &cracked_option));
 }
 
 TEST_F(IsolatedContextTest, CanHandleURL) {
@@ -353,7 +355,7 @@
   std::string cracked_inner_id;
   FileSystemMountOption cracked_option;
   ASSERT_TRUE(isolated_context()->CrackVirtualPath(
-      whole_virtual_path, &cracked_id, NULL, &cracked_inner_id,
+      whole_virtual_path, &cracked_id, nullptr, &cracked_inner_id,
       &cracked_path, &cracked_option));
   ASSERT_EQ(database_fsid, cracked_id);
   ASSERT_EQ(test_virtual_path, cracked_path);
diff --git a/storage/browser/fileapi/isolated_file_system_backend.cc b/storage/browser/fileapi/isolated_file_system_backend.cc
index 84c7665..13eb8a3 100644
--- a/storage/browser/fileapi/isolated_file_system_backend.cc
+++ b/storage/browser/fileapi/isolated_file_system_backend.cc
@@ -82,12 +82,12 @@
     default:
       NOTREACHED();
   }
-  return NULL;
+  return nullptr;
 }
 
 WatcherManager* IsolatedFileSystemBackend::GetWatcherManager(
     FileSystemType type) {
-  return NULL;
+  return nullptr;
 }
 
 CopyOrMoveFileValidatorFactory*
@@ -95,7 +95,7 @@
     FileSystemType type, base::File::Error* error_code) {
   DCHECK(error_code);
   *error_code = base::File::FILE_OK;
-  return NULL;
+  return nullptr;
 }
 
 FileSystemOperation* IsolatedFileSystemBackend::CreateFileSystemOperation(
@@ -143,22 +143,22 @@
 
 FileSystemQuotaUtil* IsolatedFileSystemBackend::GetQuotaUtil() {
   // No quota support.
-  return NULL;
+  return nullptr;
 }
 
 const UpdateObserverList* IsolatedFileSystemBackend::GetUpdateObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 const ChangeObserverList* IsolatedFileSystemBackend::GetChangeObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 const AccessObserverList* IsolatedFileSystemBackend::GetAccessObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 }  // namespace storage
diff --git a/storage/browser/fileapi/local_file_stream_reader_unittest.cc b/storage/browser/fileapi/local_file_stream_reader_unittest.cc
index 7516d84..208a7d72 100644
--- a/storage/browser/fileapi/local_file_stream_reader_unittest.cc
+++ b/storage/browser/fileapi/local_file_stream_reader_unittest.cc
@@ -38,8 +38,8 @@
 void ReadFromReader(LocalFileStreamReader* reader,
                     std::string* data, size_t size,
                     int* result) {
-  ASSERT_TRUE(reader != NULL);
-  ASSERT_TRUE(result != NULL);
+  ASSERT_TRUE(reader != nullptr);
+  ASSERT_TRUE(result != nullptr);
   *result = net::OK;
   net::TestCompletionCallback callback;
   size_t total_bytes_read = 0;
@@ -186,7 +186,7 @@
     result = callback.WaitForResult();
   ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
 
-  // With NULL expected modification time this should work.
+  // With nullptr expected modification time this should work.
   reader.reset(CreateFileReader(test_path(), 0, base::Time()));
   result = reader->GetLength(callback.callback());
   if (result == net::ERR_IO_PENDING)
@@ -246,7 +246,7 @@
   EXPECT_EQ(net::OK, result);
   EXPECT_EQ(kTestData, data);
 
-  // And with NULL expected modification time this should work.
+  // And with nullptr expected modification time this should work.
   data.clear();
   reader.reset(CreateFileReader(test_path(), 0, base::Time()));
   ReadFromReader(reader.get(), &data, kTestDataSize, &result);
diff --git a/storage/browser/fileapi/local_file_stream_writer.cc b/storage/browser/fileapi/local_file_stream_writer.cc
index 1e8d0f87..ed6c584e 100644
--- a/storage/browser/fileapi/local_file_stream_writer.cc
+++ b/storage/browser/fileapi/local_file_stream_writer.cc
@@ -131,7 +131,7 @@
 
   if (result != net::OK) {
     has_pending_operation_ = false;
-    stream_impl_.reset(NULL);
+    stream_impl_.reset(nullptr);
     error_callback.Run(result);
     return;
   }
diff --git a/storage/browser/fileapi/local_file_util_unittest.cc b/storage/browser/fileapi/local_file_util_unittest.cc
index 8a3bc288..b0b58e6 100644
--- a/storage/browser/fileapi/local_file_util_unittest.cc
+++ b/storage/browser/fileapi/local_file_util_unittest.cc
@@ -51,11 +51,11 @@
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     file_system_context_ =
-        CreateFileSystemContextForTesting(NULL, data_dir_.GetPath());
+        CreateFileSystemContextForTesting(nullptr, data_dir_.GetPath());
   }
 
   void TearDown() override {
-    file_system_context_ = NULL;
+    file_system_context_ = nullptr;
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc
index 03f80cf..49f5f3cb8 100644
--- a/storage/browser/fileapi/obfuscated_file_util.cc
+++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -874,7 +874,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DestroyDirectoryDatabase(origin, type_string);
 
-  const base::FilePath origin_path = GetDirectoryForOrigin(origin, false, NULL);
+  const base::FilePath origin_path =
+      GetDirectoryForOrigin(origin, false, nullptr);
   if (origin_path.empty())
     return true;
 
@@ -1197,7 +1198,7 @@
   std::string key = GetDirectoryDatabaseKey(
       url.origin(), CallGetTypeStringForURL(url));
   if (key.empty())
-    return NULL;
+    return nullptr;
 
   auto iter = directories_.find(key);
   if (iter != directories_.end()) {
@@ -1210,7 +1211,7 @@
   if (error != base::File::FILE_OK) {
     LOG(WARNING) << "Failed to get origin+type directory: "
                  << url.DebugString() << " error:" << error;
-    return NULL;
+    return nullptr;
   }
   MarkUsed();
   directories_[key] =
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h
index 748d30e..ce12c819 100644
--- a/storage/browser/fileapi/obfuscated_file_util.h
+++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -282,7 +282,7 @@
   std::string GetDirectoryDatabaseKey(const GURL& origin,
                                       const std::string& type_string);
 
-  // This returns NULL if |create| flag is false and a filesystem does not
+  // This returns nullptr if |create| flag is false and a filesystem does not
   // exist for the given |url|.
   // For read operations |create| should be false.
   SandboxDirectoryDatabase* GetDirectoryDatabase(const FileSystemURL& url,
diff --git a/storage/browser/fileapi/obfuscated_file_util_unittest.cc b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
index fb67043..1fecb7a3 100644
--- a/storage/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -192,7 +192,7 @@
   }
 
   void TearDown() override {
-    quota_manager_ = NULL;
+    quota_manager_ = nullptr;
     scoped_task_environment_.RunUntilIdle();
     sandbox_file_system_.TearDown();
   }
@@ -248,7 +248,7 @@
       storage::SpecialStoragePolicy* storage_policy) {
     return std::unique_ptr<ObfuscatedFileUtil>(
         ObfuscatedFileUtil::CreateForTesting(storage_policy, data_dir_path(),
-                                             NULL));
+                                             nullptr));
   }
 
   ObfuscatedFileUtil* ofu() {
@@ -300,7 +300,7 @@
   }
 
   bool PathExists(const FileSystemURL& url) {
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
     base::File::Info file_info;
     base::FilePath platform_path;
     base::File::Error error = ofu()->GetFileInfo(
@@ -330,7 +330,7 @@
   }
 
   void CheckFileAndCloseHandle(const FileSystemURL& url, base::File file) {
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
     base::FilePath local_path;
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->GetLocalFilePath(context.get(), url, &local_path));
@@ -357,7 +357,7 @@
 
     base::File::Info file_info1;
     EXPECT_EQ(length, GetSize(data_path));
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->GetFileInfo(context.get(), url, &file_info1, &data_path));
     EXPECT_EQ(data_path, local_path);
@@ -370,12 +370,12 @@
     EXPECT_EQ(length, file_info1.size);
     EXPECT_LE(file_info0.last_modified, file_info1.last_modified);
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->Truncate(context.get(), url, length * 2));
     EXPECT_EQ(length * 2, GetSize(data_path));
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->Truncate(context.get(), url, 0));
     EXPECT_EQ(0, GetSize(data_path));
@@ -389,7 +389,7 @@
     std::set<base::FilePath::StringType>::const_iterator iter;
     for (iter = files.begin(); iter != files.end(); ++iter) {
       bool created = true;
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       ASSERT_EQ(base::File::FILE_OK,
                 ofu()->EnsureFileExists(context.get(),
                                         FileSystemURLAppend(root_url, *iter),
@@ -397,7 +397,7 @@
       ASSERT_FALSE(created);
     }
     for (iter = directories.begin(); iter != directories.end(); ++iter) {
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       EXPECT_TRUE(DirectoryExists(
           FileSystemURLAppend(root_url, *iter)));
     }
@@ -473,7 +473,7 @@
     std::set<base::FilePath::StringType>::iterator iter;
     for (iter = files->begin(); iter != files->end(); ++iter) {
       bool created = false;
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       ASSERT_EQ(base::File::FILE_OK,
                 ofu()->EnsureFileExists(context.get(),
                                         FileSystemURLAppend(root_url, *iter),
@@ -483,7 +483,7 @@
     for (iter = directories->begin(); iter != directories->end(); ++iter) {
       bool exclusive = true;
       bool recursive = false;
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       EXPECT_EQ(base::File::FILE_OK,
                 ofu()->CreateDirectory(context.get(),
                                        FileSystemURLAppend(root_url, *iter),
@@ -499,7 +499,7 @@
 
     std::unique_ptr<FileSystemOperationContext> context;
     std::vector<filesystem::mojom::DirectoryEntry> entries;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               AsyncFileTestHelper::ReadDirectory(
                   file_system_context(), root_url, &entries));
@@ -523,7 +523,7 @@
     base::Time last_access_time = base::Time::Now();
     base::Time last_modified_time = base::Time::Now();
 
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->Touch(context.get(), url, last_access_time,
                            last_modified_time));
@@ -531,7 +531,7 @@
     EXPECT_TRUE(change_observer()->HasNoChange());
     base::FilePath local_path;
     base::File::Info file_info;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK, ofu()->GetFileInfo(
         context.get(), url, &file_info, &local_path));
     // We compare as time_t here to lower our resolution, to avoid false
@@ -539,14 +539,14 @@
     // representation and back.
     EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     last_modified_time += base::TimeDelta::FromHours(1);
     last_access_time += base::TimeDelta::FromHours(14);
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->Touch(context.get(), url, last_access_time,
                            last_modified_time));
     EXPECT_TRUE(change_observer()->HasNoChange());
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->GetFileInfo(context.get(), url, &file_info, &local_path));
     EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT());
@@ -572,7 +572,7 @@
     std::unique_ptr<FileSystemOperationContext> context;
 
     if (overwrite) {
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       bool created = false;
       EXPECT_EQ(base::File::FILE_OK,
                 ofu()->EnsureFileExists(context.get(), dest_url, &created));
@@ -587,14 +587,14 @@
         ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path());
     if (!overwrite) {
       // Verify that file creation requires sufficient quota for the path.
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       context->set_allowed_bytes_growth(path_cost + src_file_length - 1);
       EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
                 ofu()->CopyInForeignFile(context.get(),
                                          src_file_path, dest_url));
     }
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     context->set_allowed_bytes_growth(path_cost + src_file_length);
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->CopyInForeignFile(context.get(),
@@ -603,7 +603,7 @@
     EXPECT_TRUE(PathExists(dest_url));
     EXPECT_FALSE(DirectoryExists(dest_url));
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     base::File::Info file_info;
     base::FilePath data_path;
     EXPECT_EQ(base::File::FILE_OK,
@@ -618,17 +618,17 @@
   }
 
   void ClearTimestamp(const FileSystemURL& url) {
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->Touch(context.get(), url, base::Time(), base::Time()));
     EXPECT_EQ(base::Time(), GetModifiedTime(url));
   }
 
   base::Time GetModifiedTime(const FileSystemURL& url) {
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
     base::FilePath data_path;
     base::File::Info file_info;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->GetFileInfo(context.get(), url, &file_info, &data_path));
     EXPECT_TRUE(change_observer()->HasNoChange());
@@ -649,19 +649,19 @@
     const FileSystemURL dest_file_url(
         FileSystemURLAppendUTF8(dest_dir_url, "fuga"));
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->CreateDirectory(context.get(), src_dir_url, true, true));
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->CreateDirectory(context.get(), dest_dir_url, true, true));
 
     bool created = false;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->EnsureFileExists(context.get(), src_file_url, &created));
     if (overwrite) {
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       EXPECT_EQ(base::File::FILE_OK,
                 ofu()->EnsureFileExists(context.get(),
                                         dest_file_url, &created));
@@ -669,7 +669,7 @@
 
     ClearTimestamp(src_dir_url);
     ClearTimestamp(dest_dir_url);
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->CopyOrMoveFile(context.get(),
                                     src_file_url, dest_file_url,
@@ -684,9 +684,9 @@
 
   void MaybeDropDatabasesAliveCaseTestBody() {
     std::unique_ptr<ObfuscatedFileUtil> file_util =
-        CreateObfuscatedFileUtil(NULL);
+        CreateObfuscatedFileUtil(nullptr);
     file_util->InitOriginDatabase(GURL(), true /*create*/);
-    ASSERT_TRUE(file_util->origin_database_ != NULL);
+    ASSERT_TRUE(file_util->origin_database_ != nullptr);
 
     // Callback to Drop DB is called while ObfuscatedFileUtilTest is
     // still alive.
@@ -694,7 +694,7 @@
     file_util->MarkUsed();
     scoped_task_environment_.RunUntilIdle();
 
-    ASSERT_TRUE(file_util->origin_database_ == NULL);
+    ASSERT_TRUE(file_util->origin_database_ == nullptr);
   }
 
   void MaybeDropDatabasesAlreadyDeletedCaseTestBody() {
@@ -702,7 +702,7 @@
     // doesn't cause a crash for use after free.
     {
       std::unique_ptr<ObfuscatedFileUtil> file_util =
-          CreateObfuscatedFileUtil(NULL);
+          CreateObfuscatedFileUtil(nullptr);
       file_util->InitOriginDatabase(GURL(), true /*create*/);
       file_util->db_flush_delay_seconds_ = 0;
       file_util->MarkUsed();
@@ -722,7 +722,7 @@
     // Create DirectoryDatabase for isolated origin.
     SandboxDirectoryDatabase* db =
         file_util->GetDirectoryDatabase(url, true /* create */);
-    ASSERT_TRUE(db != NULL);
+    ASSERT_TRUE(db != nullptr);
 
     // Destory it.
     file_util->DestroyDirectoryDatabase(
@@ -740,7 +740,7 @@
     // Create DirectoryDatabase for isolated origin.
     SandboxDirectoryDatabase* db =
         file_util->GetDirectoryDatabase(url, true /* create */);
-    ASSERT_TRUE(db != NULL);
+    ASSERT_TRUE(db != nullptr);
     ASSERT_EQ(1U, file_util->directories_.size());
 
     // Remove isolated.
@@ -829,14 +829,14 @@
 
 TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE;
 
   base::File file = ofu()->CreateOrOpen(context.get(), url, file_flags);
   EXPECT_FALSE(file.IsValid());
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->DeleteFile(context.get(), url));
 
@@ -845,14 +845,14 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 
   // Verify that file creation requires sufficient quota for the path.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
   EXPECT_FALSE(file.IsValid());
   ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE, file.error_details());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
@@ -862,7 +862,7 @@
 
   CheckFileAndCloseHandle(url, std::move(file));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   base::FilePath local_path;
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetLocalFilePath(context.get(), url, &local_path));
@@ -870,7 +870,7 @@
 
   // Verify that deleting a file isn't stopped by zero quota, and that it frees
   // up quote from its path.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(0);
   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url));
   EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
@@ -878,7 +878,7 @@
   EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()),
             context->allowed_bytes_growth());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   bool exclusive = true;
   bool recursive = true;
   FileSystemURL directory_url = CreateURLFromUTF8(
@@ -890,7 +890,7 @@
   // The oepration created 3 directories recursively.
   EXPECT_EQ(3, change_observer()->get_and_reset_create_directory_count());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   file = ofu()->CreateOrOpen(context.get(), url, file_flags);
   ASSERT_TRUE(file.IsValid());
   ASSERT_TRUE(file.created());
@@ -898,12 +898,12 @@
 
   CheckFileAndCloseHandle(url, std::move(file));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetLocalFilePath(context.get(), url, &local_path));
   EXPECT_TRUE(base::PathExists(local_path));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url));
   EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
   EXPECT_FALSE(base::PathExists(local_path));
@@ -915,29 +915,29 @@
 TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
   bool created = false;
   FileSystemURL url = CreateURLFromUTF8("file");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->Truncate(context.get(), url, 4));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   ASSERT_TRUE(created);
   EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   base::FilePath local_path;
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetLocalFilePath(context.get(), url, &local_path));
   EXPECT_EQ(0, GetSize(local_path));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 10));
   EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
   EXPECT_EQ(10, GetSize(local_path));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 1));
   EXPECT_EQ(1, GetSize(local_path));
   EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
@@ -1007,13 +1007,13 @@
 TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
   bool created = false;
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_TRUE(change_observer()->HasNoChange());
 
   // Verify that file creation requires sufficient quota for the path.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   url = CreateURLFromUTF8("test file");
   created = false;
   context->set_allowed_bytes_growth(
@@ -1023,7 +1023,7 @@
   ASSERT_FALSE(created);
   EXPECT_TRUE(change_observer()->HasNoChange());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
   ASSERT_EQ(base::File::FILE_OK,
@@ -1033,7 +1033,7 @@
 
   CheckFileAndCloseHandle(url, base::File());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   ASSERT_FALSE(created);
@@ -1041,7 +1041,7 @@
 
   // Also test in a subdirectory.
   url = CreateURLFromUTF8("path/to/file.txt");
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   bool exclusive = true;
   bool recursive = true;
   EXPECT_EQ(base::File::FILE_OK,
@@ -1050,7 +1050,7 @@
   // 2 directories: path/ and path/to.
   EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   ASSERT_TRUE(created);
@@ -1060,7 +1060,7 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   bool exclusive = false;
   bool recursive = false;
@@ -1068,17 +1068,17 @@
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->DeleteDirectory(context.get(), url));
 
   FileSystemURL root = CreateURLFromUTF8(std::string());
   EXPECT_FALSE(DirectoryExists(url));
   EXPECT_FALSE(PathExists(url));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), root));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   exclusive = false;
   recursive = true;
   EXPECT_EQ(base::File::FILE_OK,
@@ -1088,16 +1088,16 @@
   EXPECT_TRUE(DirectoryExists(url));
   EXPECT_TRUE(PathExists(url));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), root));
   EXPECT_TRUE(DirectoryExists(FileSystemURLDirName(url)));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(),
                                        FileSystemURLDirName(url)));
 
   // Can't remove a non-empty directory.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
             ofu()->DeleteDirectory(context.get(),
                                    FileSystemURLDirName(url)));
@@ -1112,21 +1112,21 @@
   EXPECT_FALSE(file_info.is_symbolic_link);
 
   // Same create again should succeed, since exclusive is false.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
 
   exclusive = true;
   recursive = true;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
 
   // Verify that deleting a directory isn't stopped by zero quota, and that it
   // frees up quota from its path.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(0);
   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url));
   EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
@@ -1138,7 +1138,7 @@
   EXPECT_FALSE(DirectoryExists(url));
   EXPECT_FALSE(PathExists(url));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->GetFileInfo(context.get(), url, &file_info, &local_path));
@@ -1146,14 +1146,14 @@
   // Verify that file creation requires sufficient quota for the path.
   exclusive = true;
   recursive = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
   EXPECT_EQ(base::File::FILE_OK,
@@ -1165,7 +1165,7 @@
 
   exclusive = true;
   recursive = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
@@ -1173,7 +1173,7 @@
   exclusive = true;
   recursive = false;
   url = CreateURLFromUTF8("foo");
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
@@ -1185,7 +1185,7 @@
 
   exclusive = true;
   recursive = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
@@ -1195,14 +1195,14 @@
 
   exclusive = true;
   recursive = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool exclusive = true;
   bool recursive = true;
   FileSystemURL url = CreateURLFromUTF8("directory/to/use");
@@ -1221,7 +1221,7 @@
 
 TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
   FileSystemURL url = CreateURLFromUTF8("file");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   bool created = false;
   ASSERT_EQ(base::File::FILE_OK,
@@ -1238,7 +1238,7 @@
 
 TEST_F(ObfuscatedFileUtilTest, TestTouch) {
   FileSystemURL url = CreateURLFromUTF8("file");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   base::Time last_access_time = base::Time::Now();
   base::Time last_modified_time = base::Time::Now();
@@ -1249,7 +1249,7 @@
                          last_modified_time));
 
   // OK, now create it.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   bool created = false;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
@@ -1257,7 +1257,7 @@
   TestTouchHelper(url, true);
 
   // Now test a directory:
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   bool exclusive = true;
   bool recursive = false;
   url = CreateURLFromUTF8("dir");
@@ -1268,7 +1268,7 @@
 
 TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   url = CreateURLFromUTF8("file name");
   context->set_allowed_bytes_growth(5);
@@ -1296,7 +1296,7 @@
     path_cost += ObfuscatedFileUtil::ComputeFilePathCost(
         base::FilePath(*iter));
   }
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(1024);
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url, exclusive, recursive));
@@ -1306,7 +1306,7 @@
 TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
   FileSystemURL source_url = CreateURLFromUTF8("path0.txt");
   FileSystemURL dest_url = CreateURLFromUTF8("path1.txt");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   bool is_copy_not_move = false;
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
@@ -1314,7 +1314,7 @@
                                   FileSystemOperation::OPTION_NONE,
                                   is_copy_not_move));
   EXPECT_TRUE(change_observer()->HasNoChange());
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   is_copy_not_move = true;
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
@@ -1324,7 +1324,7 @@
   source_url = CreateURLFromUTF8("dir/dir/file");
   bool exclusive = true;
   bool recursive = true;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(),
                 FileSystemURLDirName(source_url),
@@ -1336,7 +1336,7 @@
                                   FileSystemOperation::OPTION_NONE,
                                   is_copy_not_move));
   EXPECT_TRUE(change_observer()->HasNoChange());
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   is_copy_not_move = true;
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
@@ -1360,45 +1360,45 @@
       test_case.dest_path);
     SCOPED_TRACE(testing::Message() << "\t cause_overwrite " <<
       test_case.cause_overwrite);
-    std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+    std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
     bool exclusive = false;
     bool recursive = true;
     FileSystemURL source_url = CreateURLFromUTF8(test_case.source_path);
     FileSystemURL dest_url = CreateURLFromUTF8(test_case.dest_path);
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     ASSERT_EQ(base::File::FILE_OK,
               ofu()->CreateDirectory(context.get(),
                                      FileSystemURLDirName(source_url),
                                      exclusive, recursive));
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     ASSERT_EQ(base::File::FILE_OK,
               ofu()->CreateDirectory(context.get(),
                                      FileSystemURLDirName(dest_url),
                                      exclusive, recursive));
 
     bool created = false;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     ASSERT_EQ(base::File::FILE_OK,
               ofu()->EnsureFileExists(context.get(), source_url, &created));
     ASSERT_TRUE(created);
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     ASSERT_EQ(base::File::FILE_OK,
               ofu()->Truncate(context.get(), source_url, kSourceLength));
 
     if (test_case.cause_overwrite) {
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       created = false;
       ASSERT_EQ(base::File::FILE_OK,
                 ofu()->EnsureFileExists(context.get(), dest_url, &created));
       ASSERT_TRUE(created);
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       ASSERT_EQ(base::File::FILE_OK,
                 ofu()->Truncate(context.get(), dest_url, kDestLength));
     }
 
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
                                     FileSystemOperation::OPTION_NONE,
@@ -1407,7 +1407,7 @@
     if (test_case.is_copy_not_move) {
       base::File::Info file_info;
       base::FilePath local_path;
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       EXPECT_EQ(base::File::FILE_OK,
                 ofu()->GetFileInfo(context.get(), source_url, &file_info,
                                    &local_path));
@@ -1417,7 +1417,7 @@
     } else {
       base::File::Info file_info;
       base::FilePath local_path;
-      context.reset(NewContext(NULL));
+      context.reset(NewContext(nullptr));
       EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
                 ofu()->GetFileInfo(context.get(), source_url, &file_info,
                                    &local_path));
@@ -1437,7 +1437,7 @@
 TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool created = false;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_url, &created));
@@ -1449,7 +1449,7 @@
   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
                                   FileSystemOperation::OPTION_NONE, is_copy));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()));
   EXPECT_EQ(base::File::FILE_OK,
@@ -1457,7 +1457,7 @@
                                   FileSystemOperation::OPTION_NONE, is_copy));
 
   // Copy, with overwrite.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(0);
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
@@ -1467,21 +1467,21 @@
 TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool created = false;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_url, &created));
 
   bool is_copy = false;
   // Move, rename, no overwrite.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) -
       ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()) - 1);
   EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
                                   FileSystemOperation::OPTION_NONE, is_copy));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(
       ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) -
       ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()));
@@ -1489,12 +1489,12 @@
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
                                   FileSystemOperation::OPTION_NONE, is_copy));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_url, &created));
 
   // Move, rename, with overwrite.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(0);
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
@@ -1503,7 +1503,7 @@
 
 TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool created = false;
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_url, &created));
@@ -1511,7 +1511,7 @@
   bool exclusive = true;
   bool recursive = false;
   FileSystemURL dir_url = CreateURLFromUTF8("directory path");
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), dir_url, exclusive,
                                    recursive));
@@ -1522,7 +1522,7 @@
   bool is_copy = false;
   int64_t allowed_bytes_growth = -1000;  // Over quota, this should still work.
   // Move, no rename, no overwrite.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(allowed_bytes_growth);
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
@@ -1530,10 +1530,10 @@
   EXPECT_EQ(allowed_bytes_growth, context->allowed_bytes_growth());
 
   // Move, no rename, with overwrite.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   ASSERT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_url, &created));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   context->set_allowed_bytes_growth(allowed_bytes_growth);
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(context.get(), src_url, dest_url,
@@ -1550,7 +1550,7 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestEnumerator) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   FileSystemURL src_url = CreateURLFromUTF8("source dir");
   bool exclusive = true;
   bool recursive = false;
@@ -1669,7 +1669,7 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   int64_t expected_quota = 0;
 
@@ -1724,14 +1724,14 @@
   bool created = false;
 
   // Create a non-empty file.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), kPath1, &created));
   EXPECT_TRUE(created);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->Truncate(context.get(), kPath1, 10));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetFileInfo(
                 context.get(), kPath1, &file_info, &data_path));
@@ -1742,18 +1742,18 @@
 
   // Try to get file info of broken file.
   EXPECT_FALSE(PathExists(kPath1));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), kPath1, &created));
   EXPECT_TRUE(created);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetFileInfo(
                 context.get(), kPath1, &file_info, &data_path));
   EXPECT_EQ(0, file_info.size);
 
   // Make another broken file to |kPath2|.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), kPath2, &created));
   EXPECT_TRUE(created);
@@ -1762,7 +1762,7 @@
   ofu()->DestroyDirectoryDatabase(origin(), type_string());
 
   // Repair broken |kPath1|.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->Touch(context.get(), kPath1, base::Time::Now(),
                            base::Time::Now()));
@@ -1771,14 +1771,14 @@
   EXPECT_TRUE(created);
 
   // Copy from sound |kPath1| to broken |kPath2|.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyOrMoveFile(context.get(), kPath1, kPath2,
                                   FileSystemOperation::OPTION_NONE,
                                   true /* copy */));
 
   ofu()->DestroyDirectoryDatabase(origin(), type_string());
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   base::File file =
       ofu()->CreateOrOpen(context.get(), kPath1,
                           base::File::FLAG_READ | base::File::FLAG_CREATE);
@@ -1800,7 +1800,7 @@
 
   for (size_t i = 0; i < arraysize(kPath); ++i) {
     bool created = false;
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->EnsureFileExists(context.get(), kPath[i], &created));
     EXPECT_TRUE(created);
@@ -1825,7 +1825,7 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
 
   // Create working directory.
@@ -1836,7 +1836,7 @@
   FileSystemURL url(FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_file"));
   bool created = false;
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_TRUE(created);
@@ -1845,7 +1845,7 @@
   // non create case.
   created = true;
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_FALSE(created);
@@ -1853,12 +1853,12 @@
 
   // fail case.
   url = FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_dir");
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url, false, false));
 
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
@@ -1866,7 +1866,7 @@
   // CreateOrOpen, create case.
   url = FileSystemURLAppendUTF8(dir_url, "CreateOrOpen_file");
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   base::File file =
       ofu()->CreateOrOpen(context.get(), url,
                           base::File::FLAG_CREATE | base::File::FLAG_WRITE);
@@ -1878,7 +1878,7 @@
 
   // open case.
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   file = ofu()->CreateOrOpen(context.get(), url,
                              base::File::FLAG_OPEN | base::File::FLAG_WRITE);
   EXPECT_TRUE(file.IsValid());
@@ -1888,7 +1888,7 @@
 
   // fail case
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   file = ofu()->CreateOrOpen(context.get(), url,
                              base::File::FLAG_CREATE | base::File::FLAG_WRITE);
   EXPECT_FALSE(file.IsValid());
@@ -1900,7 +1900,7 @@
   url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir");
   FileSystemURL subdir_url(FileSystemURLAppendUTF8(url, "subdir"));
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), subdir_url,
                                    true /* exclusive */, true /* recursive */));
@@ -1911,7 +1911,7 @@
   subdir_url = FileSystemURLAppendUTF8(url, "subdir2");
   ClearTimestamp(dir_url);
   ClearTimestamp(url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), subdir_url,
                                    true /* exclusive */, true /* recursive */));
@@ -1921,7 +1921,7 @@
   // fail case.
   url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir");
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_EXISTS,
             ofu()->CreateDirectory(context.get(), url,
                                    true /* exclusive */, true /* recursive */));
@@ -1931,17 +1931,17 @@
   url = FileSystemURLAppendUTF8(dir_url, "CopyInForeignFile_file");
   FileSystemURL src_path = FileSystemURLAppendUTF8(
       dir_url, "CopyInForeignFile_src_file");
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), src_path, &created));
   EXPECT_TRUE(created);
   base::FilePath src_local_path;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetLocalFilePath(context.get(), src_path, &src_local_path));
 
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CopyInForeignFile(context.get(),
                                      src_local_path,
@@ -1950,7 +1950,7 @@
 }
 
 TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) {
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
 
   // Create working directory.
@@ -1961,20 +1961,20 @@
   FileSystemURL url = FileSystemURLAppendUTF8(
       dir_url, "DeleteFile_file");
   bool created = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url, &created));
   EXPECT_TRUE(created);
 
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->DeleteFile(context.get(), url));
   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
 
   // fail case.
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
             ofu()->DeleteFile(context.get(), url));
   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
@@ -1982,28 +1982,28 @@
   // DeleteDirectory, fail case.
   url = FileSystemURLAppendUTF8(dir_url, "DeleteDirectory_dir");
   FileSystemURL file_path(FileSystemURLAppendUTF8(url, "pakeratta"));
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url, true, true));
   created = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), file_path, &created));
   EXPECT_TRUE(created);
 
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
             ofu()->DeleteDirectory(context.get(), url));
   EXPECT_EQ(base::Time(), GetModifiedTime(dir_url));
 
   // delete case.
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->DeleteFile(context.get(), file_path));
 
   ClearTimestamp(dir_url);
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url));
   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
 }
@@ -2024,40 +2024,40 @@
   FileSystemURL url1 = FileSystemURLAppendUTF8(dir, "bar");
   FileSystemURL url2 = FileSystemURLAppendUTF8(dir, "baz");
 
-  std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL));
+  std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), dir, false, false));
 
   bool created = false;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->EnsureFileExists(context.get(), url1, &created));
   EXPECT_TRUE(created);
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->CreateDirectory(context.get(), url2, false, false));
 
   base::FilePath file_path;
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->GetLocalFilePath(context.get(), url1, &file_path));
   EXPECT_FALSE(file_path.empty());
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   EXPECT_EQ(base::File::FILE_OK,
             ofu()->Touch(context.get(), url1,
                          base::Time::Now() + base::TimeDelta::FromHours(1),
                          base::Time()));
 
-  context.reset(NewContext(NULL));
+  context.reset(NewContext(nullptr));
   std::unique_ptr<storage::FileSystemFileUtil::AbstractFileEnumerator>
       file_enum(ofu()->CreateFileEnumerator(context.get(), dir, false));
 
   int count = 0;
   base::FilePath file_path_each;
   while (!(file_path_each = file_enum->Next()).empty()) {
-    context.reset(NewContext(NULL));
+    context.reset(NewContext(nullptr));
     base::File::Info file_info;
     base::FilePath file_path;
     EXPECT_EQ(base::File::FILE_OK,
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend.cc b/storage/browser/fileapi/plugin_private_file_system_backend.cc
index 0b09b989..44cc5cc 100644
--- a/storage/browser/fileapi/plugin_private_file_system_backend.cc
+++ b/storage/browser/fileapi/plugin_private_file_system_backend.cc
@@ -106,7 +106,7 @@
       special_storage_policy, base_path_, env_override,
       base::Bind(&FileSystemIDToPluginMap::GetPluginIDForURL,
                  base::Owned(plugin_map_)),
-      std::set<std::string>(), NULL)));
+      std::set<std::string>(), nullptr)));
 }
 
 PluginPrivateFileSystemBackend::~PluginPrivateFileSystemBackend() {
@@ -163,7 +163,7 @@
 
 WatcherManager* PluginPrivateFileSystemBackend::GetWatcherManager(
     FileSystemType type) {
-  return NULL;
+  return nullptr;
 }
 
 CopyOrMoveFileValidatorFactory*
@@ -172,7 +172,7 @@
     base::File::Error* error_code) {
   DCHECK(error_code);
   *error_code = base::File::FILE_OK;
-  return NULL;
+  return nullptr;
 }
 
 FileSystemOperation* PluginPrivateFileSystemBackend::CreateFileSystemOperation(
@@ -345,17 +345,17 @@
 
 const UpdateObserverList* PluginPrivateFileSystemBackend::GetUpdateObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 const ChangeObserverList* PluginPrivateFileSystemBackend::GetChangeObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 const AccessObserverList* PluginPrivateFileSystemBackend::GetAccessObservers(
     FileSystemType type) const {
-  return NULL;
+  return nullptr;
 }
 
 ObfuscatedFileUtil* PluginPrivateFileSystemBackend::obfuscated_file_util() {
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend_unittest.cc b/storage/browser/fileapi/plugin_private_file_system_backend_unittest.cc
index f4794ff..79dfbec 100644
--- a/storage/browser/fileapi/plugin_private_file_system_backend_unittest.cc
+++ b/storage/browser/fileapi/plugin_private_file_system_backend_unittest.cc
@@ -50,8 +50,8 @@
  protected:
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
-    context_ = CreateFileSystemContextForTesting(NULL /* quota_manager_proxy */,
-                                                 data_dir_.GetPath());
+    context_ = CreateFileSystemContextForTesting(
+        nullptr /* quota_manager_proxy */, data_dir_.GetPath());
   }
 
   FileSystemURL CreateURL(const GURL& root_url, const std::string& relative) {
@@ -222,8 +222,8 @@
       context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
 
   // Delete data for kOrigin1.
-  error = backend()->DeleteOriginDataOnFileTaskRunner(
-      context_.get(), NULL, kOrigin1, kType);
+  error = backend()->DeleteOriginDataOnFileTaskRunner(context_.get(), nullptr,
+                                                      kOrigin1, kType);
   EXPECT_EQ(base::File::FILE_OK, error);
 
   // Confirm 'foo' in kOrigin1 is deleted.
diff --git a/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc b/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc
index e4023ecc..9367fe8 100644
--- a/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc
+++ b/storage/browser/fileapi/quota/quota_backend_impl_unittest.cc
@@ -46,7 +46,7 @@
 class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
  public:
   MockQuotaManagerProxy()
-      : QuotaManagerProxy(NULL, NULL),
+      : QuotaManagerProxy(nullptr, nullptr),
         storage_modified_count_(0),
         usage_(0),
         quota_(0) {}
@@ -101,7 +101,7 @@
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     in_memory_env_ = leveldb_chrome::NewMemEnv("quota");
     file_util_.reset(ObfuscatedFileUtil::CreateForTesting(
-        NULL, data_dir_.GetPath(), in_memory_env_.get()));
+        nullptr, data_dir_.GetPath(), in_memory_env_.get()));
     backend_.reset(new QuotaBackendImpl(file_task_runner(), file_util_.get(),
                                         &file_system_usage_cache_,
                                         quota_manager_proxy_.get()));
@@ -109,7 +109,7 @@
 
   void TearDown() override {
     backend_.reset();
-    quota_manager_proxy_ = NULL;
+    quota_manager_proxy_ = nullptr;
     file_util_.reset();
     base::RunLoop().RunUntilIdle();
   }
@@ -119,7 +119,7 @@
                                   storage::FileSystemType type) {
     ASSERT_TRUE(
         file_util_->InitOriginDatabase(origin.GetURL(), true /* create */));
-    ASSERT_TRUE(file_util_->origin_database_ != NULL);
+    ASSERT_TRUE(file_util_->origin_database_ != nullptr);
 
     std::string type_string =
         SandboxFileSystemBackendDelegate::GetTypeString(type);
diff --git a/storage/browser/fileapi/quota/quota_reservation_manager_unittest.cc b/storage/browser/fileapi/quota/quota_reservation_manager_unittest.cc
index 06c97e0..1e73a3a 100644
--- a/storage/browser/fileapi/quota/quota_reservation_manager_unittest.cc
+++ b/storage/browser/fileapi/quota/quota_reservation_manager_unittest.cc
@@ -255,7 +255,7 @@
   EXPECT_EQ(3, fake_backend()->on_disk_usage());
   EXPECT_EQ(3 + 5, fake_backend()->on_memory_usage());
 
-  reservation = NULL;
+  reservation = nullptr;
 
   EXPECT_EQ(3, fake_backend()->on_memory_usage());
 }
@@ -289,7 +289,7 @@
             fake_backend()->on_memory_usage());
   EXPECT_EQ(kInitialFileSize + 20 + 30 + 40, fake_backend()->on_disk_usage());
 
-  reservation = NULL;
+  reservation = nullptr;
 
   EXPECT_EQ(kInitialFileSize + 20 + 30 + 40, fake_backend()->on_disk_usage());
 }
@@ -333,10 +333,10 @@
             fake_backend()->on_memory_usage());
   EXPECT_EQ(kInitialFileSize + 10 + 20, fake_backend()->on_disk_usage());
 
-  reservation1 = NULL;
+  reservation1 = nullptr;
   EXPECT_EQ(kInitialFileSize + 10 + 20 + 3, fake_backend()->on_memory_usage());
 
-  reservation2 = NULL;
+  reservation2 = nullptr;
   EXPECT_EQ(kInitialFileSize + 10 + 20, fake_backend()->on_memory_usage());
 }
 
@@ -357,13 +357,13 @@
     reservation1->OnClientCrash();
     writer.ClearWithoutUsageReport();
   }
-  reservation1 = NULL;
+  reservation1 = nullptr;
 
   EXPECT_EQ(kInitialFileSize + 10, GetFileSize(file_path()));
   EXPECT_EQ(kInitialFileSize + 15 + 20, fake_backend()->on_memory_usage());
   EXPECT_EQ(kInitialFileSize + 10, fake_backend()->on_disk_usage());
 
-  reservation2 = NULL;
+  reservation2 = nullptr;
   EXPECT_EQ(kInitialFileSize + 10, fake_backend()->on_memory_usage());
 }
 
diff --git a/storage/browser/fileapi/sandbox_directory_database_unittest.cc b/storage/browser/fileapi/sandbox_directory_database_unittest.cc
index fb294e7..dfaf01ed 100644
--- a/storage/browser/fileapi/sandbox_directory_database_unittest.cc
+++ b/storage/browser/fileapi/sandbox_directory_database_unittest.cc
@@ -51,7 +51,7 @@
     // Call CloseDatabase() to avoid having multiple database instances for
     // single directory at once.
     CloseDatabase();
-    db_.reset(new SandboxDirectoryDatabase(path(), NULL));
+    db_.reset(new SandboxDirectoryDatabase(path(), nullptr));
   }
 
   void CloseDatabase() {
@@ -105,7 +105,7 @@
     db_.reset();
     ASSERT_TRUE(base::DeleteFile(path(), true /* recursive */));
     ASSERT_TRUE(base::CreateDirectory(path()));
-    db_.reset(new SandboxDirectoryDatabase(path(), NULL));
+    db_.reset(new SandboxDirectoryDatabase(path(), nullptr));
   }
 
   bool RepairDatabase() {
@@ -524,10 +524,10 @@
 
 TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_Consistent) {
   FileId dir_id;
-  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
+  CreateFile(0, FPL("foo"), FPL("hoge"), nullptr);
   CreateDirectory(0, FPL("bar"), &dir_id);
-  CreateFile(dir_id, FPL("baz"), FPL("fuga"), NULL);
-  CreateFile(dir_id, FPL("fizz"), FPL("buzz"), NULL);
+  CreateFile(dir_id, FPL("baz"), FPL("fuga"), nullptr);
+  CreateFile(dir_id, FPL("fizz"), FPL("buzz"), nullptr);
 
   EXPECT_TRUE(db()->IsFileSystemConsistent());
 }
@@ -535,17 +535,17 @@
 TEST_F(SandboxDirectoryDatabaseTest,
        TestConsistencyCheck_BackingMultiEntry) {
   const base::FilePath::CharType kBackingFileName[] = FPL("the celeb");
-  CreateFile(0, FPL("foo"), kBackingFileName, NULL);
+  CreateFile(0, FPL("foo"), kBackingFileName, nullptr);
 
   EXPECT_TRUE(db()->IsFileSystemConsistent());
   ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false));
-  CreateFile(0, FPL("bar"), kBackingFileName, NULL);
+  CreateFile(0, FPL("bar"), kBackingFileName, nullptr);
   EXPECT_FALSE(db()->IsFileSystemConsistent());
 }
 
 TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_FileLost) {
   const base::FilePath::CharType kBackingFileName[] = FPL("hoge");
-  CreateFile(0, FPL("foo"), kBackingFileName, NULL);
+  CreateFile(0, FPL("foo"), kBackingFileName, nullptr);
 
   EXPECT_TRUE(db()->IsFileSystemConsistent());
   ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false));
@@ -553,7 +553,7 @@
 }
 
 TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_OrphanFile) {
-  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
+  CreateFile(0, FPL("foo"), FPL("hoge"), nullptr);
 
   EXPECT_TRUE(db()->IsFileSystemConsistent());
 
@@ -601,7 +601,7 @@
   FileId dir2_id;
   CreateDirectory(0, FPL("foo"), &dir1_id);
   CreateDirectory(dir1_id, FPL("bar"), &dir2_id);
-  CreateFile(dir2_id, FPL("baz"), FPL("fizz/buzz"), NULL);
+  CreateFile(dir2_id, FPL("baz"), FPL("fizz/buzz"), nullptr);
 
   EXPECT_TRUE(db()->IsFileSystemConsistent());
   DeleteHierarchyLink(dir2_id);  // Delete link from |dir1_id| to |dir2_id|.
@@ -612,7 +612,7 @@
   base::FilePath::StringType kFileName = FPL("bar");
 
   FileId file_id_prev;
-  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
+  CreateFile(0, FPL("foo"), FPL("hoge"), nullptr);
   CreateFile(0, kFileName, FPL("fuga"), &file_id_prev);
 
   const base::FilePath kDatabaseDirectory =
@@ -633,8 +633,8 @@
 TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_Failure) {
   base::FilePath::StringType kFileName = FPL("bar");
 
-  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
-  CreateFile(0, kFileName, FPL("fuga"), NULL);
+  CreateFile(0, FPL("foo"), FPL("hoge"), nullptr);
+  CreateFile(0, kFileName, FPL("fuga"), nullptr);
 
   const base::FilePath kDatabaseDirectory =
       path().Append(kDirectoryDatabaseName);
@@ -655,7 +655,7 @@
   base::FilePath::StringType kFileName = FPL("bar");
 
   FileId file_id_prev;
-  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
+  CreateFile(0, FPL("foo"), FPL("hoge"), nullptr);
   CreateFile(0, kFileName, FPL("fuga"), &file_id_prev);
 
   const base::FilePath kDatabaseDirectory =
diff --git a/storage/browser/fileapi/sandbox_file_system_backend.cc b/storage/browser/fileapi/sandbox_file_system_backend.cc
index 9b38f2f..15b8a73 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend.cc
+++ b/storage/browser/fileapi/sandbox_file_system_backend.cc
@@ -53,12 +53,12 @@
 
   // Set quota observers.
   delegate_->RegisterQuotaUpdateObserver(storage::kFileSystemTypeTemporary);
-  delegate_->AddFileAccessObserver(
-      storage::kFileSystemTypeTemporary, delegate_->quota_observer(), NULL);
+  delegate_->AddFileAccessObserver(storage::kFileSystemTypeTemporary,
+                                   delegate_->quota_observer(), nullptr);
 
   delegate_->RegisterQuotaUpdateObserver(storage::kFileSystemTypePersistent);
-  delegate_->AddFileAccessObserver(
-      storage::kFileSystemTypePersistent, delegate_->quota_observer(), NULL);
+  delegate_->AddFileAccessObserver(storage::kFileSystemTypePersistent,
+                                   delegate_->quota_observer(), nullptr);
 }
 
 void SandboxFileSystemBackend::ResolveURL(const FileSystemURL& url,
@@ -87,7 +87,7 @@
 
 WatcherManager* SandboxFileSystemBackend::GetWatcherManager(
     FileSystemType type) {
-  return NULL;
+  return nullptr;
 }
 
 CopyOrMoveFileValidatorFactory*
@@ -96,7 +96,7 @@
     base::File::Error* error_code) {
   DCHECK(error_code);
   *error_code = base::File::FILE_OK;
-  return NULL;
+  return nullptr;
 }
 
 FileSystemOperation* SandboxFileSystemBackend::CreateFileSystemOperation(
@@ -110,7 +110,7 @@
   std::unique_ptr<FileSystemOperationContext> operation_context =
       delegate_->CreateFileSystemOperationContext(url, context, error_code);
   if (!operation_context)
-    return NULL;
+    return nullptr;
 
   SpecialStoragePolicy* policy = delegate_->special_storage_policy();
   if (policy && policy->IsStorageUnlimited(url.origin()))
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
index fedd1918..94c63c3 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
+++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -479,7 +479,7 @@
   std::map<FileSystemType, UpdateObserverList>::const_iterator iter =
       update_observers_.find(type);
   if (iter == update_observers_.end())
-    return NULL;
+    return nullptr;
   return &iter->second;
 }
 
@@ -488,7 +488,7 @@
   std::map<FileSystemType, ChangeObserverList>::const_iterator iter =
       change_observers_.find(type);
   if (iter == change_observers_.end())
-    return NULL;
+    return nullptr;
   return &iter->second;
 }
 
@@ -497,7 +497,7 @@
   std::map<FileSystemType, AccessObserverList>::const_iterator iter =
       access_observers_.find(type);
   if (iter == access_observers_.end())
-    return NULL;
+    return nullptr;
   return &iter->second;
 }
 
@@ -704,12 +704,9 @@
     storage::SpecialStoragePolicy* special_storage_policy,
     const base::FilePath& file_system_directory,
     leveldb::Env* env_override) {
-  return new ObfuscatedFileUtil(special_storage_policy,
-                                file_system_directory,
-                                env_override,
-                                base::Bind(&GetTypeStringForURL),
-                                GetKnownTypeStrings(),
-                                NULL);
+  return new ObfuscatedFileUtil(special_storage_policy, file_system_directory,
+                                env_override, base::Bind(&GetTypeStringForURL),
+                                GetKnownTypeStrings(), nullptr);
 }
 
 }  // namespace storage
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc b/storage/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
index cf49cd91..c8dce44 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
+++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
@@ -42,7 +42,7 @@
         nullptr, base::ThreadTaskRunnerHandle::Get().get());
     delegate_.reset(new storage::SandboxFileSystemBackendDelegate(
         quota_manager_proxy_.get(), base::ThreadTaskRunnerHandle::Get().get(),
-        data_dir_.GetPath(), NULL /* special_storage_policy */,
+        data_dir_.GetPath(), nullptr /* special_storage_policy */,
         CreateAllowFileAccessOptions(), nullptr /* env_override */));
   }
 
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_unittest.cc b/storage/browser/fileapi/sandbox_file_system_backend_unittest.cc
index 4f0017f..a5b3df8 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend_unittest.cc
+++ b/storage/browser/fileapi/sandbox_file_system_backend_unittest.cc
@@ -258,10 +258,9 @@
   for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "RootPath (create=false) #" << i << " "
                  << kRootPathTestCases[i].expected_path);
-    EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
-                             kRootPathTestCases[i].type,
-                             storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
-                             NULL));
+    EXPECT_FALSE(GetRootPath(
+        GURL(kRootPathTestCases[i].origin_url), kRootPathTestCases[i].type,
+        storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, nullptr));
   }
 }
 
@@ -272,10 +271,9 @@
   for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "RootPath (incognito) #" << i << " "
                  << kRootPathTestCases[i].expected_path);
-    EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
-                             kRootPathTestCases[i].type,
-                             storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-                             NULL));
+    EXPECT_FALSE(GetRootPath(
+        GURL(kRootPathTestCases[i].origin_url), kRootPathTestCases[i].type,
+        storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, nullptr));
   }
 }
 
@@ -287,7 +285,7 @@
     EXPECT_FALSE(GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
                              kRootPathFileURITestCases[i].type,
                              storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-                             NULL));
+                             nullptr));
   }
 }
 
diff --git a/storage/browser/fileapi/sandbox_origin_database_unittest.cc b/storage/browser/fileapi/sandbox_origin_database_unittest.cc
index e2675a76..d89ebb28 100644
--- a/storage/browser/fileapi/sandbox_origin_database_unittest.cc
+++ b/storage/browser/fileapi/sandbox_origin_database_unittest.cc
@@ -42,7 +42,7 @@
   EXPECT_FALSE(base::PathExists(kFSDir));
   EXPECT_TRUE(base::CreateDirectory(kFSDir));
 
-  SandboxOriginDatabase database(kFSDir, NULL);
+  SandboxOriginDatabase database(kFSDir, nullptr);
   std::string origin("origin");
 
   EXPECT_FALSE(database.HasOriginPath(origin));
@@ -72,7 +72,7 @@
   EXPECT_FALSE(base::PathExists(kFSDir));
   EXPECT_TRUE(base::CreateDirectory(kFSDir));
 
-  SandboxOriginDatabase database(kFSDir, NULL);
+  SandboxOriginDatabase database(kFSDir, nullptr);
   std::string origin0("origin0");
   std::string origin1("origin1");
 
@@ -100,7 +100,7 @@
   EXPECT_FALSE(base::PathExists(kFSDir));
   EXPECT_TRUE(base::CreateDirectory(kFSDir));
 
-  SandboxOriginDatabase database(kFSDir, NULL);
+  SandboxOriginDatabase database(kFSDir, nullptr);
   std::string origin("origin");
 
   EXPECT_FALSE(database.HasOriginPath(origin));
@@ -128,7 +128,7 @@
   EXPECT_FALSE(base::PathExists(kFSDir));
   EXPECT_TRUE(base::CreateDirectory(kFSDir));
 
-  SandboxOriginDatabase database(kFSDir, NULL);
+  SandboxOriginDatabase database(kFSDir, nullptr);
   std::string origin("origin");
 
   EXPECT_FALSE(database.HasOriginPath(origin));
@@ -157,7 +157,7 @@
 
   std::vector<SandboxOriginDatabase::OriginRecord> origins;
 
-  SandboxOriginDatabase database(kFSDir, NULL);
+  SandboxOriginDatabase database(kFSDir, nullptr);
   EXPECT_TRUE(database.ListAllOrigins(&origins));
   EXPECT_TRUE(origins.empty());
   origins.clear();
@@ -214,7 +214,7 @@
   };
 
   std::unique_ptr<SandboxOriginDatabase> database(
-      new SandboxOriginDatabase(kFSDir, NULL));
+      new SandboxOriginDatabase(kFSDir, nullptr));
   for (size_t i = 0; i < arraysize(kOrigins); ++i) {
     base::FilePath path;
     EXPECT_FALSE(database->HasOriginPath(kOrigins[i]));
@@ -243,7 +243,7 @@
   CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1);
 
   base::FilePath path;
-  database.reset(new SandboxOriginDatabase(kFSDir, NULL));
+  database.reset(new SandboxOriginDatabase(kFSDir, nullptr));
   std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
   EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
 
@@ -284,7 +284,7 @@
     base::FilePath path;
 
     std::unique_ptr<SandboxOriginDatabase> database(
-        new SandboxOriginDatabase(kFSDir, NULL));
+        new SandboxOriginDatabase(kFSDir, nullptr));
     EXPECT_FALSE(database->HasOriginPath(kOrigin));
     EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
     EXPECT_FALSE(path.empty());
@@ -294,7 +294,7 @@
 
     DeleteDatabaseFile(kDBDir, kLevelDBFileTypes[i]);
 
-    database.reset(new SandboxOriginDatabase(kFSDir, NULL));
+    database.reset(new SandboxOriginDatabase(kFSDir, nullptr));
     std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
     EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
 
diff --git a/storage/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc b/storage/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
index e21f418..5e1a106e 100644
--- a/storage/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
+++ b/storage/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
@@ -22,7 +22,7 @@
   const std::string kOrigin1("origin1");
   const std::string kOrigin2("origin2");
 
-  SandboxPrioritizedOriginDatabase database(dir.GetPath(), NULL);
+  SandboxPrioritizedOriginDatabase database(dir.GetPath(), nullptr);
 
   // Set the kOrigin1 as a parimary origin.
   EXPECT_TRUE(database.InitializePrimaryOrigin(kOrigin1));
@@ -76,7 +76,7 @@
   const std::string kOrigin1("origin1");
   const std::string kOrigin2("origin2");
 
-  SandboxPrioritizedOriginDatabase database(dir.GetPath(), NULL);
+  SandboxPrioritizedOriginDatabase database(dir.GetPath(), nullptr);
 
   EXPECT_TRUE(database.GetPrimaryOrigin().empty());
 
@@ -105,7 +105,7 @@
   const std::string kOrigin1("origin1");
   const std::string kData("foo");
 
-  SandboxPrioritizedOriginDatabase database(dir.GetPath(), NULL);
+  SandboxPrioritizedOriginDatabase database(dir.GetPath(), nullptr);
 
   EXPECT_TRUE(database.GetPrimaryOrigin().empty());
 
@@ -149,7 +149,7 @@
   // Initialize the directory with two origins using the regular
   // SandboxOriginDatabase.
   {
-    SandboxOriginDatabase database_old(dir.GetPath(), NULL);
+    SandboxOriginDatabase database_old(dir.GetPath(), nullptr);
     base::FilePath old_db_path = database_old.GetDatabasePath();
     EXPECT_FALSE(base::PathExists(old_db_path));
 
@@ -177,7 +177,7 @@
   }
 
   // Re-open the directory using sandboxPrioritizedOriginDatabase.
-  SandboxPrioritizedOriginDatabase database(dir.GetPath(), NULL);
+  SandboxPrioritizedOriginDatabase database(dir.GetPath(), nullptr);
 
   // Set the kOrigin1 as a parimary origin.
   // (Trying to initialize another origin should fail).
diff --git a/storage/browser/fileapi/task_runner_bound_observer_list.h b/storage/browser/fileapi/task_runner_bound_observer_list.h
index a244b6a..4dad36c4 100644
--- a/storage/browser/fileapi/task_runner_bound_observer_list.h
+++ b/storage/browser/fileapi/task_runner_bound_observer_list.h
@@ -39,7 +39,7 @@
   virtual ~TaskRunnerBoundObserverList() {}
 
   // Returns a new observer list with given observer.
-  // It is valid to give NULL as |runner_to_notify|, and in that case
+  // It is valid to give nullptr as |runner_to_notify|, and in that case
   // notifications are dispatched on the current runner.
   // Note that this is a const method and does NOT change 'this' observer
   // list but returns a new list.
diff --git a/storage/browser/fileapi/transient_file_util.cc b/storage/browser/fileapi/transient_file_util.cc
index 892776cd..fd0a24f 100644
--- a/storage/browser/fileapi/transient_file_util.cc
+++ b/storage/browser/fileapi/transient_file_util.cc
@@ -47,7 +47,7 @@
       ScopedFile::DELETE_ON_SCOPE_OUT,
       context->task_runner());
   scoped_file.AddScopeOutCallback(
-      base::BindOnce(&RevokeFileSystem, url.filesystem_id()), NULL);
+      base::BindOnce(&RevokeFileSystem, url.filesystem_id()), nullptr);
 
   return scoped_file;
 }
diff --git a/storage/browser/fileapi/transient_file_util_unittest.cc b/storage/browser/fileapi/transient_file_util_unittest.cc
index 922419d..0567b32 100644
--- a/storage/browser/fileapi/transient_file_util_unittest.cc
+++ b/storage/browser/fileapi/transient_file_util_unittest.cc
@@ -29,14 +29,14 @@
 
   void SetUp() override {
     file_system_context_ = CreateFileSystemContextForTesting(
-        NULL, base::FilePath(FILE_PATH_LITERAL("dummy")));
+        nullptr, base::FilePath(FILE_PATH_LITERAL("dummy")));
     transient_file_util_.reset(new storage::TransientFileUtil);
 
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
   }
 
   void TearDown() override {
-    file_system_context_ = NULL;
+    file_system_context_ = nullptr;
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc
index afda0ed..732fe4a 100644
--- a/storage/browser/quota/client_usage_tracker.cc
+++ b/storage/browser/quota/client_usage_tracker.cc
@@ -159,7 +159,7 @@
                            delta);
 
     // Notify the usage monitor that usage has changed. The storage monitor may
-    // be NULL during tests.
+    // be nullptr during tests.
     if (storage_monitor_) {
       StorageObserver::Filter filter(type_, origin);
       storage_monitor_->NotifyUsageChange(filter, delta);
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc
index e759bcf4..9103809e 100644
--- a/storage/browser/quota/quota_database.cc
+++ b/storage/browser/quota/quota_database.cc
@@ -38,7 +38,7 @@
 const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped";
 
 bool VerifyValidQuotaConfig(const char* key) {
-  return (key != NULL &&
+  return (key != nullptr &&
           (!strcmp(key, QuotaDatabase::kDesiredAvailableSpaceKey) ||
            !strcmp(key, QuotaDatabase::kTemporaryQuotaOverrideKey)));
 }
diff --git a/storage/browser/quota/quota_database_unittest.cc b/storage/browser/quota/quota_database_unittest.cc
index c42503d..ff4774d 100644
--- a/storage/browser/quota/quota_database_unittest.cc
+++ b/storage/browser/quota/quota_database_unittest.cc
@@ -154,7 +154,7 @@
 
     std::set<GURL> exceptions;
     GURL origin;
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_TRUE(origin.is_empty());
 
     const GURL kOrigin1("http://a/");
@@ -174,7 +174,7 @@
     EXPECT_TRUE(db.SetOriginLastAccessTime(kOrigin4, kPersistent,
                                            base::Time::FromInternalValue(40)));
 
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_EQ(kOrigin1.spec(), origin.spec());
 
     // Test that unlimited origins are exluded from eviction, but
@@ -192,15 +192,15 @@
     EXPECT_EQ(kOrigin3.spec(), origin.spec());
 
     exceptions.insert(kOrigin1);
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_EQ(kOrigin2.spec(), origin.spec());
 
     exceptions.insert(kOrigin2);
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_EQ(kOrigin3.spec(), origin.spec());
 
     exceptions.insert(kOrigin3);
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_TRUE(origin.is_empty());
 
     EXPECT_TRUE(
@@ -211,12 +211,12 @@
 
     // Querying again to see if the deletion has worked.
     exceptions.clear();
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_EQ(kOrigin2.spec(), origin.spec());
 
     exceptions.insert(kOrigin1);
     exceptions.insert(kOrigin2);
-    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, NULL, &origin));
+    EXPECT_TRUE(db.GetLRUOrigin(kTemporary, exceptions, nullptr, &origin));
     EXPECT_TRUE(origin.is_empty());
   }
 
@@ -466,7 +466,7 @@
  private:
   template <typename Iterator>
   void AssignQuotaTable(sql::Database* db, Iterator itr, Iterator end) {
-    ASSERT_NE(db, (sql::Database*)NULL);
+    ASSERT_NE(db, (sql::Database*)nullptr);
     for (; itr != end; ++itr) {
       const char* kSql =
           "INSERT INTO HostQuotaTable"
@@ -485,7 +485,7 @@
 
   template <typename Iterator>
   void AssignOriginInfoTable(sql::Database* db, Iterator itr, Iterator end) {
-    ASSERT_NE(db, (sql::Database*)NULL);
+    ASSERT_NE(db, (sql::Database*)nullptr);
     for (; itr != end; ++itr) {
       const char* kSql =
           "INSERT INTO OriginInfoTable"
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index 59c97c9..41a92cc 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -1138,7 +1138,7 @@
 }
 
 QuotaManager::~QuotaManager() {
-  proxy_->manager_ = NULL;
+  proxy_->manager_ = nullptr;
   for (auto* client : clients_)
     client->OnQuotaManagerDestroyed();
   if (database_)
@@ -1228,11 +1228,11 @@
     case StorageType::kSyncable:
       return syncable_usage_tracker_.get();
     case StorageType::kQuotaNotManaged:
-      return NULL;
+      return nullptr;
     case StorageType::kUnknown:
       NOTREACHED();
   }
-  return NULL;
+  return nullptr;
 }
 
 void QuotaManager::GetCachedOrigins(
diff --git a/storage/browser/quota/quota_manager_proxy.h b/storage/browser/quota/quota_manager_proxy.h
index b3ab592..32b3292 100644
--- a/storage/browser/quota/quota_manager_proxy.h
+++ b/storage/browser/quota/quota_manager_proxy.h
@@ -59,7 +59,7 @@
                                 UsageAndQuotaCallback callback);
 
   // This method may only be called on the IO thread.
-  // It may return NULL if the manager has already been deleted.
+  // It may return nullptr if the manager has already been deleted.
   QuotaManager* quota_manager() const;
 
  protected:
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index 5412489..174a262 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -98,7 +98,7 @@
 
   void TearDown() override {
     // Make sure the quota manager cleans up correctly.
-    quota_manager_ = NULL;
+    quota_manager_ = nullptr;
     scoped_task_environment_.RunUntilIdle();
   }
 
@@ -288,7 +288,7 @@
   }
 
   void GetCachedOrigins(StorageType type, std::set<GURL>* origins) {
-    ASSERT_TRUE(origins != NULL);
+    ASSERT_TRUE(origins != nullptr);
     origins->clear();
     quota_manager_->GetCachedOrigins(type, origins);
   }
@@ -611,7 +611,7 @@
 }
 
 TEST_F(QuotaManagerTest, GetUsage_EmptyClient) {
-  RegisterClient(CreateClient(NULL, 0, QuotaClient::kFileSystem));
+  RegisterClient(CreateClient(nullptr, 0, QuotaClient::kFileSystem));
   GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp);
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(QuotaStatusCode::kOk, status());
@@ -983,7 +983,7 @@
   DeleteOriginData(GURL("http://bar.com/"), kTemp, kAllClients);
 
   // Nuke before waiting for callbacks.
-  set_quota_manager(NULL);
+  set_quota_manager(nullptr);
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(QuotaStatusCode::kErrorAbort, status());
 }
@@ -1155,7 +1155,7 @@
 }
 
 TEST_F(QuotaManagerTest, GetAndSetPerststentHostQuota) {
-  RegisterClient(CreateClient(NULL, 0, QuotaClient::kFileSystem));
+  RegisterClient(CreateClient(nullptr, 0, QuotaClient::kFileSystem));
 
   GetPersistentHostQuota("foo.com");
   scoped_task_environment_.RunUntilIdle();
@@ -1182,7 +1182,7 @@
 }
 
 TEST_F(QuotaManagerTest, GetAndSetPersistentUsageAndQuota) {
-  RegisterClient(CreateClient(NULL, 0, QuotaClient::kFileSystem));
+  RegisterClient(CreateClient(nullptr, 0, QuotaClient::kFileSystem));
 
   GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kPerm);
   scoped_task_environment_.RunUntilIdle();
@@ -1212,7 +1212,7 @@
 }
 
 TEST_F(QuotaManagerTest, GetSyncableQuota) {
-  RegisterClient(CreateClient(NULL, 0, QuotaClient::kFileSystem));
+  RegisterClient(CreateClient(nullptr, 0, QuotaClient::kFileSystem));
 
   // Pre-condition check: available disk space (for testing) is less than
   // the default quota for syncable storage.
@@ -1302,7 +1302,7 @@
   RunAdditionalUsageAndQuotaTask(GURL("http://bar.com/"), kPerm);
 
   // Nuke before waiting for callbacks.
-  set_quota_manager(NULL);
+  set_quota_manager(nullptr);
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(QuotaStatusCode::kErrorAbort, status());
 }
diff --git a/storage/browser/quota/quota_task.cc b/storage/browser/quota/quota_task.cc
index 8e10a880..b7266c4 100644
--- a/storage/browser/quota/quota_task.cc
+++ b/storage/browser/quota/quota_task.cc
@@ -43,7 +43,7 @@
 
 void QuotaTask::Abort() {
   DCHECK(original_task_runner_->BelongsToCurrentThread());
-  observer_ = NULL;
+  observer_ = nullptr;
   Aborted();
 }
 
diff --git a/storage/browser/quota/storage_monitor_unittest.cc b/storage/browser/quota/storage_monitor_unittest.cc
index 0ffb6b1f..e633d22 100644
--- a/storage/browser/quota/storage_monitor_unittest.cc
+++ b/storage/browser/quota/storage_monitor_unittest.cc
@@ -118,7 +118,8 @@
   const StorageObserver::Event* GetPendingEvent(
       const StorageObserverList& observer_list) {
     return observer_list.notification_timer_.IsRunning()
-                ? &observer_list.pending_event_ : NULL;
+               ? &observer_list.pending_event_
+               : nullptr;
   }
 
   const StorageObserver::Event* GetPendingEvent(
@@ -169,7 +170,7 @@
 
   void TearDown() override {
     // This ensures the quota manager is destroyed correctly.
-    quota_manager_ = NULL;
+    quota_manager_ = nullptr;
     scoped_task_environment_.RunUntilIdle();
   }
 
@@ -200,7 +201,7 @@
   observer_list.OnStorageChange(event);
   EXPECT_EQ(1, mock_observer.EventCount());
   EXPECT_EQ(event, mock_observer.LastEvent());
-  EXPECT_EQ(NULL, GetPendingEvent(observer_list));
+  EXPECT_EQ(nullptr, GetPendingEvent(observer_list));
   EXPECT_EQ(0, GetRequiredUpdatesCount(observer_list));
 
   // Verify that the next event is pending.
@@ -219,7 +220,7 @@
   observer_list.OnStorageChange(event);
   EXPECT_EQ(2, mock_observer.EventCount());
   EXPECT_EQ(event, mock_observer.LastEvent());
-  EXPECT_EQ(NULL, GetPendingEvent(observer_list));
+  EXPECT_EQ(nullptr, GetPendingEvent(observer_list));
   EXPECT_EQ(0, GetRequiredUpdatesCount(observer_list));
 
   // Remove the observer.
@@ -228,7 +229,7 @@
   observer_list.RemoveObserver(&mock_observer);
   observer_list.OnStorageChange(event);
   EXPECT_EQ(2, mock_observer.EventCount());
-  EXPECT_EQ(NULL, GetPendingEvent(observer_list));
+  EXPECT_EQ(nullptr, GetPendingEvent(observer_list));
 }
 
 // Test dispatching events to multiple observers.
@@ -258,7 +259,7 @@
   EXPECT_EQ(1, mock_observer2.EventCount());
   EXPECT_EQ(event, mock_observer1.LastEvent());
   EXPECT_EQ(event, mock_observer2.LastEvent());
-  EXPECT_EQ(NULL, GetPendingEvent(observer_list));
+  EXPECT_EQ(nullptr, GetPendingEvent(observer_list));
   EXPECT_EQ(0, GetRequiredUpdatesCount(observer_list));
 
   // Fake the last notification time so that observer1 will receive the next
@@ -281,7 +282,7 @@
   EXPECT_EQ(2, mock_observer2.EventCount());
   EXPECT_EQ(event, mock_observer1.LastEvent());
   EXPECT_EQ(event, mock_observer2.LastEvent());
-  EXPECT_EQ(NULL, GetPendingEvent(observer_list));
+  EXPECT_EQ(nullptr, GetPendingEvent(observer_list));
   EXPECT_EQ(0, GetRequiredUpdatesCount(observer_list));
 }
 
@@ -365,7 +366,7 @@
   EXPECT_EQ(1, mock_observer2.EventCount());
   EXPECT_EQ(expected_event, mock_observer2.LastEvent());
   EXPECT_TRUE(host_observers.is_initialized());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 
   // Verify that both observers will receive events after a usage change.
@@ -377,7 +378,7 @@
   EXPECT_EQ(2, mock_observer2.EventCount());
   EXPECT_EQ(expected_event, mock_observer1.LastEvent());
   EXPECT_EQ(expected_event, mock_observer2.LastEvent());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 
   // Verify that the addition of a third observer only causes an event to be
@@ -429,7 +430,7 @@
   host_observers.NotifyUsageChange(params.filter, 9438);
   EXPECT_EQ(0, mock_observer.EventCount());
   EXPECT_FALSE(host_observers.is_initialized());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 
   // Now ensure that quota manager returns a good status.
@@ -456,7 +457,7 @@
   host_observers.NotifyUsageChange(params.filter, 7645);
   EXPECT_EQ(0, mock_observer.EventCount());
   EXPECT_FALSE(host_observers.is_initialized());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 
   // Simulate notifying |host_observers| of a usage change before initialization
@@ -467,7 +468,7 @@
   host_observers.NotifyUsageChange(params.filter, kDelta);
   EXPECT_EQ(0, mock_observer.EventCount());
   EXPECT_FALSE(host_observers.is_initialized());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 
   // Simulate an asynchronous callback from QuotaManager.
@@ -477,7 +478,7 @@
   EXPECT_EQ(1, mock_observer.EventCount());
   EXPECT_EQ(expected_event, mock_observer.LastEvent());
   EXPECT_TRUE(host_observers.is_initialized());
-  EXPECT_EQ(NULL, GetPendingEvent(host_observers));
+  EXPECT_EQ(nullptr, GetPendingEvent(host_observers));
   EXPECT_EQ(0, GetRequiredUpdatesCount(host_observers));
 }
 
@@ -534,7 +535,7 @@
 class StorageMonitorTest : public StorageTestWithManagerBase {
  public:
   StorageMonitorTest()
-      : storage_monitor_(NULL),
+      : storage_monitor_(nullptr),
         params1_(StorageType::kTemporary,
                  GURL(kDefaultOrigin),
                  base::TimeDelta::FromHours(1),
@@ -630,17 +631,15 @@
         false, data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get(),
         storage_policy_.get(), storage::GetQuotaSettingsFunc());
 
-    client_ = new MockStorageClient(quota_manager_->proxy(),
-                                    NULL,
-                                    QuotaClient::kFileSystem,
-                                    0);
+    client_ = new MockStorageClient(quota_manager_->proxy(), nullptr,
+                                    QuotaClient::kFileSystem, 0);
 
     quota_manager_->proxy()->RegisterClient(client_);
   }
 
   void TearDown() override {
     // This ensures the quota manager is destroyed correctly.
-    quota_manager_ = NULL;
+    quota_manager_ = nullptr;
     scoped_task_environment_.RunUntilIdle();
   }
 
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc
index 3e641b8a..48ea323 100644
--- a/storage/browser/quota/usage_tracker_unittest.cc
+++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -140,7 +140,7 @@
         usage_tracker_(GetUsageTrackerList(),
                        StorageType::kTemporary,
                        storage_policy_.get(),
-                       NULL) {}
+                       nullptr) {}
 
   ~UsageTrackerTest() override = default;
 
diff --git a/storage/browser/test/async_file_test_helper.h b/storage/browser/test/async_file_test_helper.h
index 41e7978..fcdc0856 100644
--- a/storage/browser/test/async_file_test_helper.h
+++ b/storage/browser/test/async_file_test_helper.h
@@ -99,7 +99,8 @@
   static bool DirectoryExists(storage::FileSystemContext* context,
                               const storage::FileSystemURL& url);
 
-  // Returns usage and quota. It's valid to pass NULL to |usage| and/or |quota|.
+  // Returns usage and quota. It's valid to pass nullptr to |usage| and/or
+  // |quota|.
   static blink::mojom::QuotaStatusCode GetUsageAndQuota(
       storage::QuotaManager* quota_manager,
       const GURL& origin,
diff --git a/storage/browser/test/mock_quota_manager_proxy.cc b/storage/browser/test/mock_quota_manager_proxy.cc
index 410fb4f4..048b2afd 100644
--- a/storage/browser/test/mock_quota_manager_proxy.cc
+++ b/storage/browser/test/mock_quota_manager_proxy.cc
@@ -16,7 +16,7 @@
       storage_modified_count_(0),
       last_notified_type_(blink::mojom::StorageType::kUnknown),
       last_notified_delta_(0),
-      registered_client_(NULL) {}
+      registered_client_(nullptr) {}
 
 void MockQuotaManagerProxy::RegisterClient(QuotaClient* client) {
   DCHECK(!registered_client_);
@@ -28,7 +28,7 @@
     // We cannot call this in the destructor as the client (indirectly)
     // holds a refptr of the proxy.
     registered_client_->OnQuotaManagerDestroyed();
-    registered_client_ = NULL;
+    registered_client_ = nullptr;
   }
 }
 
diff --git a/storage/browser/test/mock_quota_manager_proxy.h b/storage/browser/test/mock_quota_manager_proxy.h
index 976b9dc..d2f41293f 100644
--- a/storage/browser/test/mock_quota_manager_proxy.h
+++ b/storage/browser/test/mock_quota_manager_proxy.h
@@ -22,7 +22,7 @@
 
 class MockQuotaManagerProxy : public QuotaManagerProxy {
  public:
-  // It is ok to give NULL to |quota_manager|.
+  // It is ok to give nullptr to |quota_manager|.
   MockQuotaManagerProxy(MockQuotaManager* quota_manager,
                         base::SingleThreadTaskRunner* task_runner);
 
diff --git a/storage/browser/test/mock_quota_manager_unittest.cc b/storage/browser/test/mock_quota_manager_unittest.cc
index 9fc112d..4ffb207 100644
--- a/storage/browser/test/mock_quota_manager_unittest.cc
+++ b/storage/browser/test/mock_quota_manager_unittest.cc
@@ -53,7 +53,7 @@
 
   void TearDown() override {
     // Make sure the quota manager cleans up correctly.
-    manager_ = NULL;
+    manager_ = nullptr;
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/storage/browser/test/sandbox_file_system_test_helper.cc b/storage/browser/test/sandbox_file_system_test_helper.cc
index a1b4f0a..cc2d38cb 100644
--- a/storage/browser/test/sandbox_file_system_test_helper.cc
+++ b/storage/browser/test/sandbox_file_system_test_helper.cc
@@ -31,19 +31,17 @@
 SandboxFileSystemTestHelper::SandboxFileSystemTestHelper(
     const GURL& origin,
     storage::FileSystemType type)
-    : origin_(origin), type_(type), file_util_(NULL) {
-}
+    : origin_(origin), type_(type), file_util_(nullptr) {}
 
 SandboxFileSystemTestHelper::SandboxFileSystemTestHelper()
     : origin_(GURL("http://foo.com")),
       type_(storage::kFileSystemTypeTemporary),
-      file_util_(NULL) {
-}
+      file_util_(nullptr) {}
 
 SandboxFileSystemTestHelper::~SandboxFileSystemTestHelper() = default;
 
 void SandboxFileSystemTestHelper::SetUp(const base::FilePath& base_dir) {
-  SetUp(base_dir, NULL);
+  SetUp(base_dir, nullptr);
 }
 
 void SandboxFileSystemTestHelper::SetUp(
@@ -63,7 +61,7 @@
 }
 
 void SandboxFileSystemTestHelper::TearDown() {
-  file_system_context_ = NULL;
+  file_system_context_ = nullptr;
   base::RunLoop().RunUntilIdle();
 }
 
@@ -132,13 +130,13 @@
 void SandboxFileSystemTestHelper::AddFileChangeObserver(
     storage::FileChangeObserver* observer) {
   file_system_context_->sandbox_delegate()->AddFileChangeObserver(
-      type_, observer, NULL);
+      type_, observer, nullptr);
 }
 
 void SandboxFileSystemTestHelper::AddFileUpdateObserver(
     storage::FileUpdateObserver* observer) {
   file_system_context_->sandbox_delegate()->AddFileUpdateObserver(
-      type_, observer, NULL);
+      type_, observer, nullptr);
 }
 
 storage::FileSystemUsageCache* SandboxFileSystemTestHelper::usage_cache() {
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index e28f745..2b86716 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -1480,6 +1480,54 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "NRD91N",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -3883,6 +3931,34 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_type": "coho",
+              "os": "Android"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -5451,6 +5527,34 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_type": "gce_x86",
+              "os": "Android"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 8e833fe..7bfac0e 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1336,6 +1336,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -3946,6 +3992,53 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84Z",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -6668,6 +6761,54 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY48I",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -9431,6 +9572,54 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY49B",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 120,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -12223,6 +12412,53 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -14925,6 +15161,53 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MRA58Z",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -18014,6 +18297,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -20687,6 +21016,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 7e92952..6af67d37 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -524,6 +524,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -1146,6 +1157,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index b96d80f..31cc347 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -203,6 +203,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -866,6 +877,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -1672,6 +1694,22 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2820,6 +2858,22 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -3956,6 +4010,22 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -5586,6 +5656,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -8331,6 +8447,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -10393,6 +10555,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -11052,6 +11225,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -11681,6 +11865,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -12320,6 +12515,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -12969,6 +13175,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -13530,6 +13747,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -13939,7 +14167,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -14098,6 +14327,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -14650,6 +14890,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -15310,6 +15561,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -15970,6 +16232,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -16630,6 +16903,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -17290,6 +17574,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -17950,6 +18245,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -18610,6 +18916,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -19270,6 +19587,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -19930,6 +20258,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -20590,6 +20929,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -21252,6 +21602,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -22029,6 +22390,22 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index fb27fde8..b37e3a1 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -441,6 +441,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -850,7 +861,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -1044,6 +1056,9 @@
         }
       },
       {
+        "args": [
+          "--extra-browser-args=--disable-gpu"
+        ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
         "swarming": {
@@ -1054,7 +1069,7 @@
       },
       {
         "args": [
-          "--extra-browser-args=--enable-features=VizDisplayCompositor"
+          "--extra-browser-args=--enable-features=VizDisplayCompositor --disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests_viz",
@@ -2096,6 +2111,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2941,7 +2967,8 @@
           "--remote=127.0.0.1",
           "--remote-ssh-port=9222",
           "--skip=telemetry.internal.app.android_app_unittest.AndroidAppTest.testWebView",
-          "--skip=telemetry.internal.backends.browser_backend_unittest.BrowserBackendIntegrationTest.testSmokeIsBrowserRunningReturnFalse"
+          "--skip=telemetry.internal.backends.browser_backend_unittest.BrowserBackendIntegrationTest.testSmokeIsBrowserRunningReturnFalse",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -3481,6 +3508,17 @@
         "test": "content_browsertests"
       },
       {
+        "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -3746,6 +3784,17 @@
         "test": "content_browsertests"
       },
       {
+        "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -4163,6 +4212,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -4692,7 +4752,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -4935,6 +4996,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -5464,7 +5536,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -5694,6 +5767,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend,ViewsBrowserWindows",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor,ViewsBrowserWindows"
         ],
         "name": "viz_content_browsertests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index b668a584..22df7c2 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -131,6 +131,17 @@
         "test": "content_browsertests"
       },
       {
+        "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -436,6 +447,17 @@
         "test": "content_browsertests"
       },
       {
+        "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1029,6 +1051,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -1562,7 +1595,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -1824,6 +1858,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -2320,7 +2365,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -2551,6 +2597,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2980,7 +3037,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -3379,6 +3437,22 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -4287,7 +4361,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index c8f79c3..bc2fddf5 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -124,6 +124,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -536,7 +547,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -718,6 +730,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -1130,7 +1153,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -1427,6 +1451,23 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12.6"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2223,7 +2264,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -2424,6 +2466,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2823,7 +2876,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -2843,7 +2897,6 @@
       {
         "alternate_swarming_dimensions": [
           {
-            "gpu": "8086:0a2e",
             "os": "Mac-10.12.6"
           }
         ],
@@ -2860,7 +2913,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:0a2e",
               "os": "Mac-10.13"
             }
           ],
@@ -3018,6 +3070,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -3420,7 +3483,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 35ffe13..e85584ae 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -825,6 +825,52 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-surface-synchronization",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -2926,6 +2972,19 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*",
+          "--test-launcher-batch-limit=1",
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor",
           "--test-launcher-batch-limit=1",
           "--test-launcher-print-test-stdio=always"
@@ -3788,6 +3847,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -4467,6 +4537,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -5087,6 +5168,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -5705,6 +5797,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
@@ -6273,6 +6376,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -6776,6 +6890,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 4907f30..ae099bac 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1793,7 +1793,7 @@
           "hard_timeout": 25200,
           "ignore_task_failure": false,
           "io_timeout": 1800,
-          "shards": 5,
+          "shards": 26,
           "upload_test_results": true
         },
         "trigger_script": {
diff --git a/testing/buildbot/chromium.swarm.json b/testing/buildbot/chromium.swarm.json
index 15a97646..528b87c 100644
--- a/testing/buildbot/chromium.swarm.json
+++ b/testing/buildbot/chromium.swarm.json
@@ -713,7 +713,8 @@
         "args": [
           "--browser=cros-chrome",
           "--remote=variable_chromeos_device_hostname",
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 4e1b640..7ed58c7 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -190,6 +190,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -689,7 +700,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -922,6 +934,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor",
           "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
         ],
@@ -1536,6 +1559,17 @@
         "test": "content_browsertests"
       },
       {
+        "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -2030,7 +2064,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "experiment_percentage": 100,
         "isolate_name": "telemetry_unittests",
@@ -2252,6 +2287,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -2736,7 +2782,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -2984,6 +3031,17 @@
       },
       {
         "args": [
+          "--enable-features=TracingPerfettoBackend",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_browsertests",
@@ -3497,7 +3555,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index ec53bc6d..100360d 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -244,7 +244,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
@@ -487,7 +488,8 @@
       },
       {
         "args": [
-          "--jobs=1"
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 0ed1fa5..91874ae8 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -216,10 +216,6 @@
 -PredictorBrowserTest.SubframeInitiatesPreconnects
 -PredictorBrowserTest.SubframeLearning
 
-# Variations appending not working when network service is enabled.
-# http://crbug.com/857165
--VariationsHttpHeadersBrowserTest.TestStrippingHeadersFromSubresourceRequest
-
 # https://crbug.com/773295
 # Remove this test when there are no more clients left that use URLFetcher.
 -VariationsHttpHeadersBrowserTest.TestStrippingHeadersFromInternalRequest
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 0b09f26..e4dffe12 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -21,16 +21,11 @@
 -PreviewsStateBrowserTest.ShouldEnableLoFiModeReload
 -PreviewsStateBrowserTest.ShouldEnableLoFiModeReloadDisableLoFi
 
--AsyncResourceHandlerBrowserTest/AsyncResourceHandlerBrowserTest.UploadProgress*
-
 # services/network/url_loader.cc should handle failure in
 # URLLoaderImpl::OnResponseBodyStreamRead(). Note this is flaky, so it will pass
 # sometimes.
 -SRC_ClearKey/EncryptedMediaTest.FrameSizeChangeVideo/0
 
-# Cross-origin request to file:// URL should be blocked. crbug.com/759230
--BrowserSideNavigationBrowserDisableWebSecurityTest.ValidateBaseUrlForDataUrl
-
 # https://crbug.com/846352: CORB/NetworkService: Remove
 # CrossSiteDocumentResourceHandler while preserving test coverage - the tests
 # below can be probably removed altogether once NetworkService ships and the
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index ee0365b0..acab9b2 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1649,7 +1649,6 @@
         # TODO(crbug.com/853356): Switch this to 10.13.
         'use_multi_dimension_trigger_script': True,
         'alternate_swarming_dimensions': [{
-          'gpu': '8086:0a2e',
           'os': 'Mac-10.12.6',
         }],
 
@@ -1658,7 +1657,6 @@
         'swarming': {
           'dimension_sets': [
             {
-              'gpu': '8086:0a2e',
               'os': 'Mac-10.13',
             },
           ],
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7847c5ff..6ebd10e 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -449,6 +449,9 @@
         # Always fails.
         '--skip=telemetry.internal.app.android_app_unittest.AndroidAppTest.testWebView',
         '--skip=telemetry.internal.backends.browser_backend_unittest.BrowserBackendIntegrationTest.testSmokeIsBrowserRunningReturnFalse',
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+        '--extra-browser-args=--disable-gpu',
       ],
       'swarming': {
         'hard_timeout': 1200,
@@ -476,6 +479,9 @@
         '--browser=cros-chrome',
         '--remote=variable_chromeos_device_hostname',
         '--jobs=1',
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+        '--extra-browser-args=--disable-gpu',
       ],
       'swarming': {
         'idempotent': False,  # https://crbug.com/549140
@@ -565,6 +571,13 @@
         'shards': 3,
       },
     },
+    'perfetto_content_browsertests': {
+      'args': [
+        '--enable-features=TracingPerfettoBackend',
+        '--gtest_filter=TracingControllerTest.*',
+      ],
+      'test': 'content_browsertests',
+    },
     'services_unittests': {},
     'shell_dialogs_unittests': {},
     'skia_unittests': {},
@@ -858,6 +871,9 @@
     'telemetry_unittests': {
       'args': [
         '--jobs=1',
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+        '--extra-browser-args=--disable-gpu',
       ],
       'swarming': {
         'idempotent': False,  # https://crbug.com/549140
@@ -896,6 +912,9 @@
     'telemetry_unittests': {
       'args': [
         '--jobs=1',
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+        '--extra-browser-args=--disable-gpu',
       ],
       'swarming': {
         'idempotent': False,  # https://crbug.com/549140
@@ -1653,6 +1672,9 @@
       'isolate_name': 'telemetry_unittests',
       'args': [
         '--extra-browser-args=--enable-features=VizDisplayCompositor',
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+        '--extra-browser-args=--disable-gpu',
       ],
       'swarming': {
         'idempotent': False,  # https://crbug.com/549140
@@ -1660,6 +1682,11 @@
       },
      },
      'telemetry_unittests': {
+       'args': [
+        # Disable GPU compositing, telemetry_unittests runs on VMs.
+        # https://crbug.com/871955
+         '--extra-browser-args=--disable-gpu',
+       ],
        'swarming': {
          'idempotent': False,  # https://crbug.com/549140
          'shards': 4,
diff --git a/third_party/WebKit/LayoutTests/.gitattributes b/third_party/WebKit/LayoutTests/.gitattributes
index 7617434..b5982ab 100644
--- a/third_party/WebKit/LayoutTests/.gitattributes
+++ b/third_party/WebKit/LayoutTests/.gitattributes
@@ -141,6 +141,7 @@
 http/tests/security/isolatedWorld/resources/userGestureEvents-second-window.html -crlf
 http/tests/security/isolatedWorld/userGestureEvents.html -crlf
 http/tests/security/resources/empty-svg.php -crlf
+media/controls/*.mht -crlf
 media/track/captions-webvtt/captions-multiline-lf.vtt -crlf
 mhtml/*.mht -crlf
 platform/win/fast/events/panScroll-event-fired.html -crlf
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 01a8fc81..3c5fb56 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -70,11 +70,8 @@
 crbug.com/591099 css3/flexbox/line-wrapping.html [ Failure ]
 crbug.com/591099 css3/flexbox/scrollbars-auto.html [ Failure ]
 crbug.com/714962 css3/masking/clip-path-reference-box-inline.html [ Failure ]
-crbug.com/591099 editing/inserting/insert-character-in-first-letter-crash.html [ Crash ]
 crbug.com/591099 editing/selection/continuations-with-move-caret-to-boundary.html [ Failure Pass ]
 crbug.com/591099 editing/selection/paint-hyphen.html [ Pass ]
-crbug.com/591099 editing/text-iterator/first-letter-word-boundary.html [ Crash ]
-crbug.com/591099 editing/text-iterator/read-past-cloned-first-letter.html [ Crash ]
 crbug.com/591099 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Pass ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html [ Timeout ]
@@ -423,10 +420,6 @@
 crbug.com/807708 fast/css-intrinsic-dimensions/width-avoid-floats.html [ Failure ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/591099 fast/css/case-transform.html [ Failure ]
-crbug.com/591099 fast/css/first-letter-block-form-controls-crash.html [ Crash ]
-crbug.com/591099 fast/css/first-letter-capitalized-edit-select-crash.html [ Crash ]
-crbug.com/591099 fast/css/first-letter-crash-document-disposal.html [ Crash ]
-crbug.com/591099 fast/css/first-letter-text-fragment-crash.html [ Crash ]
 crbug.com/835484 fast/css/focus-ring-continuations.html [ Failure ]
 crbug.com/835484 fast/css/focus-ring-recursive-continuations.html [ Failure ]
 crbug.com/835484 fast/css/focus-ring-recursive-inlines.html [ Failure ]
@@ -449,7 +442,6 @@
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
 crbug.com/591099 fast/replaced/table-replaced-element.html [ Failure ]
 crbug.com/591099 fast/ruby/position-after.html [ Failure ]
-crbug.com/591099 fast/ruby/ruby-first-letter.html [ Crash ]
 crbug.com/591099 fast/scrolling/content-box-smaller-than-scrollbar.html [ Failure ]
 crbug.com/591099 fast/scrolling/jquery-rtl-scroll-type.html [ Failure ]
 crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index b998fe3..dcbfebf 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2704,6 +2704,19 @@
 crbug.com/870526 external/wpt/push-api/idlharness.https.any.serviceworker.html [ Skip ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-007.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-005.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-multiline-002.svg [ Failure ]
+crbug.com/626703 [ Linux Win ] external/wpt/svg/text/reftests/text-multiline-003.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-201.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-001.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/painting/reftests/markers-orient-001.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-002.svg [ Failure ]
+crbug.com/626703 external/wpt/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-006.svg [ Failure ]
+crbug.com/626703 [ Linux Win ] external/wpt/svg/text/reftests/text-inline-size-003.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-multiline-001.svg [ Failure ]
+crbug.com/626703 external/wpt/svg/text/reftests/text-inline-size-101.svg [ Failure ]
 crbug.com/626703 [ Linux Win ] external/wpt/css/css-contain/contain-size-025.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-contain/contain-paint-clip-016.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-contain/contain-layout-cell-001.html [ Failure ]
@@ -3035,7 +3048,6 @@
 crbug.com/626703 external/wpt/css/css-transitions/transition-property-025.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-transitions/transition-property-013.html [ Skip ]
 crbug.com/626703 external/wpt/payment-request/show-method-postmessage-manual.https.html [ Skip ]
-crbug.com/626703 external/wpt/payment-request/payment-request-canmakepayment-method-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-writing-modes/available-size-019.html [ Failure ]
 crbug.com/626703 external/wpt/payment-request/change-shipping-option-select-last-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html [ Skip ]
@@ -3289,7 +3301,6 @@
 crbug.com/648295 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-speak-twice.html [ Timeout ]
 crbug.com/626703 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ]
-crbug.com/642912 external/wpt/wasm/wasm_indexeddb_test.https.html [ Failure ]
 crbug.com/642912 external/wpt/wasm/wasm_local_iframe_test.html [ Failure ]
 crbug.com/642912 external/wpt/wasm/wasm_serialization_tests.html [ Failure ]
 crbug.com/642912 external/wpt/wasm/wasm_service_worker_test.https.html [ Failure ]
@@ -3977,6 +3988,7 @@
 crbug.com/626703 [ Win7 ] external/wpt/domxpath/xml_xpath_runner.html [ Timeout Pass ]
 
 crbug.com/746128 [ Win7 Debug ] media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ]
+crbug.com/746128 [ Mac ] media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure Pass ]
 crbug.com/746128 [ Win7 Debug ] virtual/new-remote-playback-pipeline/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ]
 crbug.com/746128 [ Mac ] virtual/new-remote-playback-pipeline/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure Pass ]
 
@@ -4520,6 +4532,7 @@
 
 # Sheriff 2018-04-13
 crbug.com/832842 [ Win7 Linux ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ]
+crbug.com/832842 [ Mac ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure Pass ]
 crbug.com/833655 [ Linux ] media/controls/closed-captions-dynamic-update.html [ Skip ]
 crbug.com/833655 [ Linux ] virtual/new-remote-playback-pipeline/media/controls/closed-captions-dynamic-update.html [ Skip ]
 crbug.com/833655 [ Linux ] virtual/video-surface-layer/media/controls/closed-captions-dynamic-update.html [ Skip ]
@@ -4746,7 +4759,6 @@
 crbug.com/824539 [ Android ] editing/selection/previous-line-position.html [ Failure ]
 crbug.com/824539 [ Android ] editing/style/block-styles-007.html [ Failure ]
 crbug.com/824539 [ Android ] external/wpt/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.html [ Crash Failure ]
-crbug.com/824539 [ Android ] external/wpt/dom/historical.html [ Failure ]
 crbug.com/824539 [ Android ] external/wpt/gamepad/idlharness.html [ Failure ]
 crbug.com/824539 [ Android ] external/wpt/input-events/idlharness.html [ Failure ]
 crbug.com/824539 [ Android ] external/wpt/web-animations/timing-model/animations/finishing-an-animation.html [ Failure ]
@@ -4867,12 +4879,20 @@
 
 # Flaky middleClinkAutoscroll increased flakiness on Mac
 crbug.com/851090 [ Mac ] fast/events/middleClickAutoscroll-click-hyperlink.html [ Failure Pass ]
-crbug.com/851090 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs.html [ Failure Pass ]
-crbug.com/851090 [ Mac ] fast/events/middleClickAutoscroll-nested-divs.html [ Failure Pass ]
+crbug.com/851090 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs.html [ Failure Pass Timeout ]
+crbug.com/851090 [ Mac ] fast/events/middleClickAutoscroll-nested-divs.html [ Failure Pass Timeout ]
 crbug.com/851090 [ Mac ] virtual/user-activation-v2/fast/events/autoscroll-over-scrollbar.html [ Failure Pass ]
 
-# Sherrif 2018-08-08
+# Sheriff 2018-08-08
 crbug.com/871105 [ Linux ] svg/dom/remove-use-target-element-indirectly.html [ Pass Crash ]
 crbug.com/872025 [ Mac Linux ] fast/css-grid-layout/crash-large-positions.html [ Pass Timeout ]
 crbug.com/871416 fast/spatial-navigation/snav-stay-in-overflow-div.html [ Pass Failure ]
 crbug.com/872242 [ Mac ] fast/events/autoscroll-over-scrollbar.html [ Pass Failure ]
+
+# Only passes on bots with GPUs.
+crbug.com/871445 [ Mac ] http/tests/media/video-load-metadata-decode-error.html [ Timeout ]
+
+# Sheriff 2018-08-09
+crbug.com/872635 [ Mac ] fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Failure Pass ]
+crbug.com/872705 [ Mac ] virtual/mouseevent_fractional/fast/events/autoscroll-over-scrollbar.html [ Failure Pass ]
+crbug.com/872705 [ Mac ] virtual/mouseevent_fractional/fast/events/recorded-keydown-event.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers-expected.txt
index 722793b..0a00cef 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers-expected.txt
@@ -7,5 +7,5 @@
 Overflow scroll with inline child:
 PASS did not repaint when unexpected
 Overflow hidden:
-PASS repainted when expected
+PASS did not repaint when unexpected
 
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html b/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
index b9ef429..d5a56eb 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
@@ -100,7 +100,7 @@
 
     async function testOverflowHidden() {
         container.style.overflow = "hidden";
-        var result = await testScrollRepaint("Overflow hidden", true, container);
+        var result = testScrollRepaint("Overflow hidden", false, container);
         container.style.overflow = "scroll";
         return result;
     }
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index a8654db..c58001e 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -5245,12 +5245,6 @@
      {}
     ]
    ],
-   "payment-request/payment-request-canmakepayment-method-manual.https.html": [
-    [
-     "/payment-request/payment-request-canmakepayment-method-manual.https.html",
-     {}
-    ]
-   ],
    "payment-request/payment-response/complete-method-manual.https.html": [
     [
      "/payment-request/payment-response/complete-method-manual.https.html",
@@ -53059,6 +53053,18 @@
      {}
     ]
    ],
+   "css/css-pseudo/first-letter-and-sibling-display-change.html": [
+    [
+     "/css/css-pseudo/first-letter-and-sibling-display-change.html",
+     [
+      [
+       "/css/css-pseudo/first-letter-block-to-inline-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-pseudo/first-letter-block-to-inline.html": [
     [
      "/css/css-pseudo/first-letter-block-to-inline.html",
@@ -58507,6 +58513,18 @@
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html": [
+    [
+     "/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html",
+     [
+      [
+       "/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/overflow-wrap/word-wrap-001.html": [
     [
      "/css/css-text/overflow-wrap/word-wrap-001.html",
@@ -96771,6 +96789,18 @@
      {}
     ]
    ],
+   "svg/painting/reftests/markers-orient-001.svg": [
+    [
+     "/svg/painting/reftests/markers-orient-001.svg",
+     [
+      [
+       "/svg/painting/reftests/markers-orient-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "svg/painting/reftests/paint-context-001.svg": [
     [
      "/svg/painting/reftests/paint-context-001.svg",
@@ -97191,6 +97221,138 @@
      {}
     ]
    ],
+   "svg/text/reftests/text-inline-size-001.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-001.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-002.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-002.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-002-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-003.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-003.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-003-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-005.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-005.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-005-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-006.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-006.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-006-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-007.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-007.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-007-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-101.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-101.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-101-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-201.svg": [
+    [
+     "/svg/text/reftests/text-inline-size-201.svg",
+     [
+      [
+       "/svg/text/reftests/text-inline-size-201-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-001.svg": [
+    [
+     "/svg/text/reftests/text-multiline-001.svg",
+     [
+      [
+       "/svg/text/reftests/text-multiline-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-002.svg": [
+    [
+     "/svg/text/reftests/text-multiline-002.svg",
+     [
+      [
+       "/svg/text/reftests/text-multiline-002-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-003.svg": [
+    [
+     "/svg/text/reftests/text-multiline-003.svg",
+     [
+      [
+       "/svg/text/reftests/text-multiline-003-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "svg/text/reftests/textpath-shape-001.svg": [
     [
      "/svg/text/reftests/textpath-shape-001.svg",
@@ -104377,11 +104539,26 @@
      {}
     ]
    ],
+   "background-fetch/idlharness.https.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "background-fetch/idlharness.https.any.serviceworker-expected.txt": [
     [
      {}
     ]
    ],
+   "background-fetch/idlharness.https.any.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "background-fetch/idlharness.https.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "background-fetch/resources/feature-name.txt": [
     [
      {}
@@ -128732,6 +128909,11 @@
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-text/support/1x1-green.png": [
     [
      {}
@@ -153262,11 +153444,6 @@
      {}
     ]
    ],
-   "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/infrastructure/urls/interfaces-for-url-manipulation/.gitkeep": [
     [
      {}
@@ -158977,11 +159154,6 @@
      {}
     ]
    ],
-   "html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/webappapis/scripting/events/messageevent-constructor.https-expected.txt": [
     [
      {}
@@ -170027,6 +170199,11 @@
      {}
     ]
    ],
+   "svg/painting/reftests/markers-orient-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
    "svg/painting/reftests/paint-context-001-ref.svg": [
     [
      {}
@@ -170197,6 +170374,61 @@
      {}
     ]
    ],
+   "svg/text/reftests/text-inline-size-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-002-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-003-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-005-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-006-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-007-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-101-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-inline-size-201-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-002-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "svg/text/reftests/text-multiline-003-ref.svg": [
+    [
+     {}
+    ]
+   ],
    "svg/text/reftests/textpath-shape-001-ref.svg": [
     [
      {}
@@ -170227,6 +170459,11 @@
      {}
     ]
    ],
+   "svg/types/scripted/event-handler-all-document-element-events-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "svg/types/scripted/resources/SVGLengthList-helper.js": [
     [
      {}
@@ -171077,6 +171314,66 @@
      {}
     ]
    ],
+   "wasm/jsapi/assertions.js": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/bad-imports.js": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/interface.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/interface.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/memory/constructor.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/memory/constructor.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/customSections.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/customSections.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/table/constructor.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/table/constructor.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/wasm-constants.js": [
+    [
+     {}
+    ]
+   ],
+   "wasm/jsapi/wasm-module-builder.js": [
+    [
+     {}
+    ]
+   ],
    "wasm/resources/blank.html": [
     [
      {}
@@ -171102,16 +171399,6 @@
      {}
     ]
    ],
-   "wasm/wasm_idb_worker.js": [
-    [
-     {}
-    ]
-   ],
-   "wasm/wasm_indexeddb_test.js": [
-    [
-     {}
-    ]
-   ],
    "wasm/wasm_serialization_tests.js": [
     [
      {}
@@ -175432,6 +175719,11 @@
      {}
     ]
    ],
+   "workers/modules/dedicated-worker-import-referrer-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "workers/modules/dedicated-worker-options-credentials.html.headers": [
     [
      {}
@@ -175902,6 +176194,21 @@
      {}
     ]
    ],
+   "worklets/animation-worklet-referrer.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "worklets/layout-worklet-referrer.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "worklets/paint-worklet-referrer.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "worklets/resources/addmodule-window.html": [
     [
      {}
@@ -183937,14 +184244,6 @@
      {}
     ]
    ],
-   "IndexedDB/wasm-module-value.html": [
-    [
-     "/IndexedDB/wasm-module-value.html",
-     {
-      "timeout": "long"
-     }
-    ]
-   ],
    "IndexedDB/writer-starvation.htm": [
     [
      "/IndexedDB/writer-starvation.htm",
@@ -185113,22 +185412,22 @@
      {}
     ]
    ],
-   "background-fetch/idlharness.any.js": [
+   "background-fetch/idlharness.https.any.js": [
     [
-     "/background-fetch/idlharness.any.html",
-     {}
-    ],
-    [
-     "/background-fetch/idlharness.any.sharedworker.html",
-     {}
-    ],
-    [
-     "/background-fetch/idlharness.any.worker.html",
+     "/background-fetch/idlharness.https.any.html",
      {}
     ],
     [
      "/background-fetch/idlharness.https.any.serviceworker.html",
      {}
+    ],
+    [
+     "/background-fetch/idlharness.https.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/background-fetch/idlharness.https.any.worker.html",
+     {}
     ]
    ],
    "background-fetch/mixed-content-and-allowed-schemes.https.window.js": [
@@ -201699,6 +201998,12 @@
      {}
     ]
    ],
+   "dom/inert/inert-does-not-match-disabled-selector.html": [
+    [
+     "/dom/inert/inert-does-not-match-disabled-selector.html",
+     {}
+    ]
+   ],
    "dom/interface-objects.html": [
     [
      "/dom/interface-objects.html",
@@ -201851,9 +202156,9 @@
      {}
     ]
    ],
-   "dom/nodes/Document-URL.sub.html": [
+   "dom/nodes/Document-URL.html": [
     [
-     "/dom/nodes/Document-URL.sub.html",
+     "/dom/nodes/Document-URL.html",
      {}
     ]
    ],
@@ -215896,19 +216201,27 @@
    "html/browsers/the-window-object/window-open-noopener.html": [
     [
      "/html/browsers/the-window-object/window-open-noopener.html?_parent",
-     {}
+     {
+      "timeout": "long"
+     }
     ],
     [
      "/html/browsers/the-window-object/window-open-noopener.html?_self",
-     {}
+     {
+      "timeout": "long"
+     }
     ],
     [
      "/html/browsers/the-window-object/window-open-noopener.html?_top",
-     {}
+     {
+      "timeout": "long"
+     }
     ],
     [
      "/html/browsers/the-window-object/window-open-noopener.html?indexed",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "html/browsers/the-window-object/window-properties.https.html": [
@@ -216935,6 +217248,52 @@
      {}
     ]
    ],
+   "html/editing/focus/inert/inert-does-not-match-disabled-selector.html": [
+    [
+     "/html/editing/focus/inert/inert-does-not-match-disabled-selector.html",
+     {}
+    ]
+   ],
+   "html/editing/focus/inert/inert-in-shadow-dom.html": [
+    [
+     "/html/editing/focus/inert/inert-in-shadow-dom.html",
+     {}
+    ]
+   ],
+   "html/editing/focus/inert/inert-inlines.html": [
+    [
+     "/html/editing/focus/inert/inert-inlines.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "html/editing/focus/inert/inert-label-focus.html": [
+    [
+     "/html/editing/focus/inert/inert-label-focus.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "html/editing/focus/inert/inert-node-is-uneditable.html": [
+    [
+     "/html/editing/focus/inert/inert-node-is-uneditable.html",
+     {}
+    ]
+   ],
+   "html/editing/focus/inert/inert-node-is-unfocusable.html": [
+    [
+     "/html/editing/focus/inert/inert-node-is-unfocusable.html",
+     {}
+    ]
+   ],
+   "html/editing/focus/inert/inert-node-is-unselectable.html": [
+    [
+     "/html/editing/focus/inert/inert-node-is-unselectable.html",
+     {}
+    ]
+   ],
    "html/editing/focus/processing-model/focus-fixup-rule-one-no-dialogs.html": [
     [
      "/html/editing/focus/processing-model/focus-fixup-rule-one-no-dialogs.html",
@@ -217173,9 +217532,15 @@
      {}
     ]
    ],
-   "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml": [
+   "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html": [
     [
-     "/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml",
+     "/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html",
+     {}
+    ]
+   ],
+   "html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml": [
+    [
+     "/html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml",
      {}
     ]
    ],
@@ -217357,6 +217722,18 @@
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html": [
+    [
+     "/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html",
+     {}
+    ]
+   ],
+   "html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html": [
+    [
+     "/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html",
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/tables/form-in-tables-xhtml.xhtml": [
     [
      "/html/rendering/non-replaced-elements/tables/form-in-tables-xhtml.xhtml",
@@ -226743,9 +227120,9 @@
      {}
     ]
    ],
-   "html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html": [
+   "html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.https.html": [
     [
-     "/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html",
+     "/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.https.html",
      {}
     ]
    ],
@@ -227011,6 +227388,18 @@
      {}
     ]
    ],
+   "intersection-observer/initial-observation-with-threshold.html": [
+    [
+     "/intersection-observer/initial-observation-with-threshold.html",
+     {}
+    ]
+   ],
+   "intersection-observer/inline-client-rect.html": [
+    [
+     "/intersection-observer/inline-client-rect.html",
+     {}
+    ]
+   ],
    "intersection-observer/isIntersecting-change-events.html": [
     [
      "/intersection-observer/isIntersecting-change-events.html",
@@ -229773,22 +230162,22 @@
      {}
     ]
    ],
-   "notifications/idlharness.any.js": [
+   "notifications/idlharness.https.any.js": [
     [
-     "/notifications/idlharness.any.html",
-     {}
-    ],
-    [
-     "/notifications/idlharness.any.sharedworker.html",
-     {}
-    ],
-    [
-     "/notifications/idlharness.any.worker.html",
+     "/notifications/idlharness.https.any.html",
      {}
     ],
     [
      "/notifications/idlharness.https.any.serviceworker.html",
      {}
+    ],
+    [
+     "/notifications/idlharness.https.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/notifications/idlharness.https.any.worker.html",
+     {}
     ]
    ],
    "notifications/instance.html": [
@@ -239609,6 +239998,14 @@
      }
     ]
    ],
+   "payment-request/payment-request-canmakepayment-method.https.html": [
+    [
+     "/payment-request/payment-request-canmakepayment-method.https.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "payment-request/payment-request-constructor-crash.https.html": [
     [
      "/payment-request/payment-request-constructor-crash.https.html",
@@ -240207,22 +240604,22 @@
      {}
     ]
    ],
-   "push-api/idlharness.any.js": [
+   "push-api/idlharness.https.any.js": [
     [
-     "/push-api/idlharness.any.html",
-     {}
-    ],
-    [
-     "/push-api/idlharness.any.sharedworker.html",
-     {}
-    ],
-    [
-     "/push-api/idlharness.any.worker.html",
+     "/push-api/idlharness.https.any.html",
      {}
     ],
     [
      "/push-api/idlharness.https.any.serviceworker.html",
      {}
+    ],
+    [
+     "/push-api/idlharness.https.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/push-api/idlharness.https.any.worker.html",
+     {}
     ]
    ],
    "quirks/blocks-ignore-line-height.html": [
@@ -253727,6 +254124,12 @@
      {}
     ]
    ],
+   "svg/types/scripted/event-handler-all-document-element-events.svg": [
+    [
+     "/svg/types/scripted/event-handler-all-document-element-events.svg",
+     {}
+    ]
+   ],
    "touch-events/historical.html": [
     [
      "/touch-events/historical.html",
@@ -254809,9 +255212,163 @@
      {}
     ]
    ],
-   "wasm/wasm_indexeddb_test.https.html": [
+   "wasm/jsapi/constructor/instantiate-bad-imports.any.js": [
     [
-     "/wasm/wasm_indexeddb_test.https.html",
+     "/wasm/jsapi/constructor/instantiate-bad-imports.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/constructor/instantiate-bad-imports.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/constructor/instantiate-bad-imports.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/instance/constructor-bad-imports.any.js": [
+    [
+     "/wasm/jsapi/instance/constructor-bad-imports.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/instance/constructor-bad-imports.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/instance/constructor-bad-imports.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/instance/constructor.any.js": [
+    [
+     "/wasm/jsapi/instance/constructor.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/instance/constructor.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/instance/constructor.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/interface.any.js": [
+    [
+     "/wasm/jsapi/interface.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/interface.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/interface.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/memory/constructor.any.js": [
+    [
+     "/wasm/jsapi/memory/constructor.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/memory/constructor.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/memory/constructor.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/constructor.any.js": [
+    [
+     "/wasm/jsapi/module/constructor.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/module/constructor.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/module/constructor.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/customSections.any.js": [
+    [
+     "/wasm/jsapi/module/customSections.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/module/customSections.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/module/customSections.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/exports.any.js": [
+    [
+     "/wasm/jsapi/module/exports.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/module/exports.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/module/exports.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/module/imports.any.js": [
+    [
+     "/wasm/jsapi/module/imports.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/module/imports.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/module/imports.any.worker.html",
+     {}
+    ]
+   ],
+   "wasm/jsapi/table/constructor.any.js": [
+    [
+     "/wasm/jsapi/table/constructor.any.html",
+     {}
+    ],
+    [
+     "/wasm/jsapi/table/constructor.any.js",
+     {
+      "jsshell": true
+     }
+    ],
+    [
+     "/wasm/jsapi/table/constructor.any.worker.html",
      {}
     ]
    ],
@@ -257283,6 +257840,12 @@
      {}
     ]
    ],
+   "webrtc/RTCIceTransport-extension.https.html": [
+    [
+     "/webrtc/RTCIceTransport-extension.https.html",
+     {}
+    ]
+   ],
    "webrtc/RTCIceTransport.html": [
     [
      "/webrtc/RTCIceTransport.html",
@@ -269330,6 +269893,54 @@
      "/css/selectors/selection-image-001-noref.html",
      {}
     ]
+   ],
+   "svg/text/visualtests/text-inline-size-001-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-001-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-002-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-002-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-003-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-003-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-005-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-005-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-006-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-006-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-007-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-007-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-101-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-101-visual.svg",
+     {}
+    ]
+   ],
+   "svg/text/visualtests/text-inline-size-201-visual.svg": [
+    [
+     "/svg/text/visualtests/text-inline-size-201-visual.svg",
+     {}
+    ]
    ]
   },
   "wdspec": {
@@ -275366,10 +275977,6 @@
    "092b2e56b4f3ca71e36fc0b7e2892535b37b7c3a",
    "support"
   ],
-  "IndexedDB/wasm-module-value.html": [
-   "71f4f3082028829ba17edcbc7fa7382d45109a30",
-   "testharness"
-  ],
   "IndexedDB/writer-starvation.htm": [
    "76b34c6324cb5191aee56de0fd94e6132e65f15a",
    "testharness"
@@ -276998,10 +277605,6 @@
    "0cfe805f5e3fe9ccaf7b3c25a061cc583e8bc38c",
    "support"
   ],
-  "background-fetch/idlharness.any.js": [
-   "5c0eebc307b9cdb534003593248b03004352dacd",
-   "testharness"
-  ],
   "background-fetch/idlharness.any.sharedworker-expected.txt": [
    "5d9b1fd7b67c0d0c557564e28e261b58d73aa78a",
    "support"
@@ -277010,10 +277613,26 @@
    "5d9b1fd7b67c0d0c557564e28e261b58d73aa78a",
    "support"
   ],
+  "background-fetch/idlharness.https.any-expected.txt": [
+   "adddfe5d5f620053d14c361792757c618b8469b1",
+   "support"
+  ],
+  "background-fetch/idlharness.https.any.js": [
+   "5c0eebc307b9cdb534003593248b03004352dacd",
+   "testharness"
+  ],
   "background-fetch/idlharness.https.any.serviceworker-expected.txt": [
    "92d77448b72d6220ad7b2d3a6b23534c99bdc9e5",
    "support"
   ],
+  "background-fetch/idlharness.https.any.sharedworker-expected.txt": [
+   "aad3232c9459c4b4eb604e3d852f0fd78346fe3b",
+   "support"
+  ],
+  "background-fetch/idlharness.https.any.worker-expected.txt": [
+   "aad3232c9459c4b4eb604e3d852f0fd78346fe3b",
+   "support"
+  ],
   "background-fetch/mixed-content-and-allowed-schemes.https.window.js": [
    "5c8d022ff16664199c2c0f7c33df883653b4f254",
    "testharness"
@@ -315591,7 +316210,7 @@
    "reftest"
   ],
   "css/css-grid/grid-layout-properties.html": [
-   "d30ee96245cf3d25bffc64347a4ee60bfb2b2049",
+   "951c53679990e675e492c201a93f1812e8026d53",
    "testharness"
   ],
   "css/css-grid/grid-model/display-grid.html": [
@@ -320002,6 +320621,10 @@
    "5a7a51802925bda01fbb62c8635a0e3205683e51",
    "reftest"
   ],
+  "css/css-pseudo/first-letter-and-sibling-display-change.html": [
+   "fe8b6b71faa344223eaa4ed781b39699e6f194b0",
+   "reftest"
+  ],
   "css/css-pseudo/first-letter-block-to-inline-ref.html": [
    "1c8ca71127b09dc729377b71b102bed8095aa249",
    "support"
@@ -325430,6 +326053,10 @@
    "ae7abc617493b9e2c9313215a3f38b77c37d9450",
    "reftest"
   ],
+  "css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html": [
+   "ef77c1be79979b43f753a3f5abbefbd50002887e",
+   "reftest"
+  ],
   "css/css-text/overflow-wrap/reference/overflow-wrap-break-word-001-ref.html": [
    "0b16a0bdb25ddd647ad96dd82e3430274667ee87",
    "support"
@@ -325454,6 +326081,10 @@
    "3686ae6a0e278a970b861c165f0f840df302db70",
    "support"
   ],
+  "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html": [
+   "f70011433ebe5f0df3040aa5d92a34f1e6ab9229",
+   "support"
+  ],
   "css/css-text/overflow-wrap/word-wrap-001.html": [
    "8bafc4d48bbfee1e6c465a95b29792ba33c30346",
    "reftest"
@@ -345027,7 +345658,7 @@
    "testharness"
   ],
   "css/cssom/interfaces-expected.txt": [
-   "9e7e2c9027e8ece2d166cf3c6c2593e9530845a7",
+   "defaf5702e2b46cdb55dd2356e8a6bc53d54f3dc",
    "support"
   ],
   "css/cssom/interfaces.html": [
@@ -352223,11 +352854,15 @@
    "support"
   ],
   "dom/historical-expected.txt": [
-   "428a35a1e289a8bea86f1b5c37aeb145e67c4d9b",
+   "26e3bf886379fb6329c7c1beb95a44bc3ee4cdf9",
    "support"
   ],
   "dom/historical.html": [
-   "291d078c4424d0491aeab7524d350eab7304f989",
+   "9015b79acc45e480c8f9abc60ab18e2bc1afd2df",
+   "testharness"
+  ],
+  "dom/inert/inert-does-not-match-disabled-selector.html": [
+   "9622a2f3fcac6a11dd215fea94e41e4365abec27",
    "testharness"
   ],
   "dom/interface-objects.html": [
@@ -352362,8 +352997,8 @@
    "4442c3a7aba3d1a9ead2a08d312dd221c0bade90",
    "support"
   ],
-  "dom/nodes/Document-URL.sub.html": [
-   "1b04398f6f5657ca4ed97d41de565fe52e1853e2",
+  "dom/nodes/Document-URL.html": [
+   "e06e90d138edbc592c317862dd83e8caf2b63af1",
    "testharness"
   ],
   "dom/nodes/Document-adoptNode.html": [
@@ -353379,7 +354014,7 @@
    "testharness"
   ],
   "dom/nodes/rootNode.html": [
-   "9e57a68d7e39fcee75bdfb737de93bd6b6236b3a",
+   "2cd3ea5d30ccb63c8ed122647928cf676ac95f34",
    "testharness"
   ],
   "dom/nodes/selectors.js": [
@@ -362375,7 +363010,7 @@
    "testharness"
   ],
   "html/browsers/the-window-object/window-open-noopener.html": [
-   "ee8d53b12b8034d1c0ede3b2c6516a345890915e",
+   "dc96e4c9c8c64ffd8fdf722383ccdfdcbcc58afb",
    "testharness"
   ],
   "html/browsers/the-window-object/window-open-noopener_indexed-expected.txt": [
@@ -367742,6 +368377,34 @@
    "c8f4cb0441b482664a145b534edee487beda31c2",
    "testharness"
   ],
+  "html/editing/focus/inert/inert-does-not-match-disabled-selector.html": [
+   "fbf2f33c8f043061328f1723dc0078781879f02f",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-in-shadow-dom.html": [
+   "2a25ceb0137bda8059ffdaef0596b42f68a30f48",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-inlines.html": [
+   "c534eaa5e2a22ac9648d7770c4b0d195fa3f9866",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-label-focus.html": [
+   "df5e73f0bc6275287e3b0eb97a3369a679b57117",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-node-is-uneditable.html": [
+   "f8d9482452deb9a031fb5bfd86d86bdf75e14316",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-node-is-unfocusable.html": [
+   "6fabb47b5fe7bc25f5be019c1669a34fdf1b91a3",
+   "testharness"
+  ],
+  "html/editing/focus/inert/inert-node-is-unselectable.html": [
+   "1f5052ab3af3a2c230b07d82679281baddbe5135",
+   "testharness"
+  ],
   "html/editing/focus/processing-model/focus-fixup-rule-one-no-dialogs.html": [
    "270a8c31ce78e9ae07d8169367224051baf91fd8",
    "testharness"
@@ -368350,12 +369013,12 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub-expected.txt": [
-   "8862b9460b11b6afbd81d9382ff79375d4f69f70",
-   "support"
+  "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html": [
+   "1bbcedf0374aa43765b097ce3dc62b48523b6778",
+   "testharness"
   ],
-  "html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml": [
-   "ed3aa629bb438b285cc30761f526e76bad8c01b8",
+  "html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml": [
+   "2b66626e70fc73f0efc1b0cd578fb82b9f24f181",
    "testharness"
   ],
   "html/infrastructure/urls/interfaces-for-url-manipulation/.gitkeep": [
@@ -369082,6 +369745,14 @@
    "f5ec83d4ee5ce80ae40a5fe12269d4c7c6c9d91a",
    "support"
   ],
+  "html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html": [
+   "caf73b26a03b47d19668850e11c97b9e085ccf9c",
+   "testharness"
+  ],
+  "html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html": [
+   "61e138ed126a194f002ba187e8d68bbba51f2c6e",
+   "testharness"
+  ],
   "html/rendering/non-replaced-elements/quotes/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
@@ -379358,10 +380029,6 @@
    "23db12066d01404453425499bbc1c85e293375cc",
    "testharness"
   ],
-  "html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event-expected.txt": [
-   "f28915679bf718c5e71d2f36cb0de26c04275564",
-   "support"
-  ],
   "html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event.html": [
    "a779db7beb4c5f52bde9131b7648b6efab2f8000",
    "testharness"
@@ -379802,7 +380469,7 @@
    "8f141c495c1b4444c8e25ba57924d7917f97d1b9",
    "testharness"
   ],
-  "html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html": [
+  "html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.https.html": [
    "d87ec96d53353fc63b9d3db4775414c6335cdd2d",
    "testharness"
   ],
@@ -381014,6 +381681,14 @@
    "6cbea44f209e59ea0b901b0fe1cec7ac1aee0b64",
    "testharness"
   ],
+  "intersection-observer/initial-observation-with-threshold.html": [
+   "1f3b96b7b22f1926eda6ba602ca1585aa96fc9db",
+   "testharness"
+  ],
+  "intersection-observer/inline-client-rect.html": [
+   "5ef7203a189e693e49b8ce52cfb29f8fa76be2d4",
+   "testharness"
+  ],
   "intersection-observer/isIntersecting-change-events.html": [
    "6def578601e9fb21f2ffd5412a83036353b7647a",
    "testharness"
@@ -381531,7 +382206,7 @@
    "testharness"
   ],
   "media-source/mediasource-changetype-util.js": [
-   "a886523b16f314c6988fc734dacfd9568b707c27",
+   "b4e57994dbc5c2862e548156d114d8110f09f006",
    "support"
   ],
   "media-source/mediasource-changetype.html": [
@@ -381731,7 +382406,7 @@
    "testharness"
   ],
   "media-source/mediasource-util.js": [
-   "72b8c59a8eb6ed9f672eac1ba237e19d0d6fc4fa",
+   "8de08141e7839f1e41cc6ac98d45afa2e57fceed",
    "support"
   ],
   "media-source/mp3/sound_5.mp3": [
@@ -384194,10 +384869,6 @@
    "5c3baf5da0b37791d9ae35033c04d0fcf5a1b318",
    "support"
   ],
-  "notifications/idlharness.any.js": [
-   "c140ff43dc93d45d611941edfdb92b42be11ba87",
-   "testharness"
-  ],
   "notifications/idlharness.any.sharedworker-expected.txt": [
    "cc3279f611cbe6e08909ef7f00e5ac151629699c",
    "support"
@@ -384206,6 +384877,10 @@
    "cc3279f611cbe6e08909ef7f00e5ac151629699c",
    "support"
   ],
+  "notifications/idlharness.https.any.js": [
+   "c140ff43dc93d45d611941edfdb92b42be11ba87",
+   "testharness"
+  ],
   "notifications/idlharness.https.any.serviceworker-expected.txt": [
    "a0511ee3c37e878f62bf0c9e3893230210d275ac",
    "support"
@@ -391359,17 +392034,17 @@
    "support"
   ],
   "payment-request/payment-request-abort-method.https.html": [
-   "a9d811dc41487ba7a8e5d55319574364b93362aa",
+   "033fb8ae8710acf8870a7ff7b36aa3d33ec86e0b",
    "testharness"
   ],
-  "payment-request/payment-request-canmakepayment-method-manual.https.html": [
-   "20edcf57236087023cf7379cec4a4ab3b57f3155",
-   "manual"
-  ],
   "payment-request/payment-request-canmakepayment-method.https-expected.txt": [
-   "edf4b9aedbdc74041e2aa49d77eaa177954f0f80",
+   "1192dd5e77f9cb197c30ebc22d8271759db8d1e2",
    "support"
   ],
+  "payment-request/payment-request-canmakepayment-method.https.html": [
+   "e2c13d3485bca29d28558ca4664745ae286bab6c",
+   "testharness"
+  ],
   "payment-request/payment-request-constructor-crash.https.html": [
    "383d1c3f9505ee63d504bee87e13efa90ba49f3d",
    "testharness"
@@ -391419,11 +392094,11 @@
    "testharness"
   ],
   "payment-request/payment-request-show-method.https.html": [
-   "5d3272b142ce55347400f8890cf406dd77804654",
+   "132a07918e43418e3da3b26128146ea9606fb8b9",
    "testharness"
   ],
   "payment-request/payment-response/complete-method-manual.https.html": [
-   "218d966b1dbf064e56010101e71fc4489c34cb45",
+   "7ead47f96f3b45cb446b967d129d2704047a85c2",
    "manual"
   ],
   "payment-request/payment-response/helpers.js": [
@@ -392558,10 +393233,6 @@
    "d1559a52f07fcb9f06d6d70c140665463d17c215",
    "support"
   ],
-  "push-api/idlharness.any.js": [
-   "72864ef8db9789fc58ec0de4dfc84249f9368ff1",
-   "testharness"
-  ],
   "push-api/idlharness.any.sharedworker-expected.txt": [
    "7b4ac8ca15e6888027a19c5e5bdef7e0109968bf",
    "support"
@@ -392570,6 +393241,10 @@
    "7b4ac8ca15e6888027a19c5e5bdef7e0109968bf",
    "support"
   ],
+  "push-api/idlharness.https.any.js": [
+   "72864ef8db9789fc58ec0de4dfc84249f9368ff1",
+   "testharness"
+  ],
   "quirks/META.yml": [
    "0214c11aec63acf1b5ae247cff64b440ff8b4bfe",
    "support"
@@ -402987,7 +403662,7 @@
    "testharness"
   ],
   "service-workers/service-worker/interfaces-sw.https-expected.txt": [
-   "8c5191a644ac762a4a5bb66c6f70b5900a3e557c",
+   "ff5c91c7d58511fab3e2c6900e69a49dd063426b",
    "support"
   ],
   "service-workers/service-worker/interfaces-sw.https.html": [
@@ -403891,7 +404566,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/interfaces-worker.sub.js": [
-   "cd067da4cc6683916037aaf13d71f6309f04460b",
+   "612ace7df6de8514c4175ab0b3f72b85541cfe14",
    "support"
   ],
   "service-workers/service-worker/resources/invalid-blobtype-iframe.https.html": [
@@ -407182,6 +407857,14 @@
    "d8e578f5422229b37676ecdc7146488ac0865eaf",
    "reftest"
   ],
+  "svg/painting/reftests/markers-orient-001-ref.svg": [
+   "be7bd408a33c09630027aa03f8fbde81d70cdf65",
+   "support"
+  ],
+  "svg/painting/reftests/markers-orient-001.svg": [
+   "97f819fac348b0124e92b38b14939179fcd07443",
+   "reftest"
+  ],
   "svg/painting/reftests/paint-context-001-ref.svg": [
    "d7e12d36f0b3168c677edf95ce401b3e1e5eccbe",
    "support"
@@ -407530,6 +408213,94 @@
    "2976a4812636c4515cc5e2c633b17c47bee392ab",
    "testharness"
   ],
+  "svg/text/reftests/text-inline-size-001-ref.svg": [
+   "01f9695fa0965609348eada7c058fc1942b81b24",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-001.svg": [
+   "c99160d090e23f53d404e3dff127cdfae7f971cc",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-002-ref.svg": [
+   "e60c2d19f59d25acb8bf6cac063d0060ff0656fd",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-002.svg": [
+   "44b683fa1c34daac7e49763bcc108976fbb94ae8",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-003-ref.svg": [
+   "5301e3cc45e4948f38df96a482afcbc4188d939f",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-003.svg": [
+   "76c25b7386d160fb2f21a8f9cd40b3e1590a40ba",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-005-ref.svg": [
+   "6f0a98878263f20824b99a40dca45201a2d55243",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-005.svg": [
+   "91a6a50635b5dfe981a83509c13d62a7c333d76b",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-006-ref.svg": [
+   "4fa3dcc4eeb69cf64e82dd8f397c73c693eb51fb",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-006.svg": [
+   "50addd6be8ecb405a6b15821907605cad9b1d9d4",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-007-ref.svg": [
+   "6d210fbd1f98bad5563e1328fcf03b0311eb33f3",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-007.svg": [
+   "614537e68a70bdacfd206096ffa0c07f04f78797",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-101-ref.svg": [
+   "58ba7fcd16c1d044386ff9e221847c589111867e",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-101.svg": [
+   "2a6be86c0522e430de9b84ab299f4e26c6e7a8cf",
+   "reftest"
+  ],
+  "svg/text/reftests/text-inline-size-201-ref.svg": [
+   "b80c4cfc11af6dd6ede27ec232a5dabf1de8f5f4",
+   "support"
+  ],
+  "svg/text/reftests/text-inline-size-201.svg": [
+   "5bb85fc9de79fb3ef741f8f1215911e590fc1462",
+   "reftest"
+  ],
+  "svg/text/reftests/text-multiline-001-ref.svg": [
+   "79dfad6caf2c10047e436f4bcdccebe0753c3b02",
+   "support"
+  ],
+  "svg/text/reftests/text-multiline-001.svg": [
+   "cdff010d68d308bd248cb834d4edc4a3af17036f",
+   "reftest"
+  ],
+  "svg/text/reftests/text-multiline-002-ref.svg": [
+   "66252b5a763750c9bfb7fe9082a6b960c408bd40",
+   "support"
+  ],
+  "svg/text/reftests/text-multiline-002.svg": [
+   "07154a1b549e1cf0eb79b356a06ce6de727fddc0",
+   "reftest"
+  ],
+  "svg/text/reftests/text-multiline-003-ref.svg": [
+   "da35a5f4c3defee2b3e63418ee5a062e1b40e517",
+   "support"
+  ],
+  "svg/text/reftests/text-multiline-003.svg": [
+   "9151f583f6d6f94108b1dd5006a5037a874d9ac3",
+   "reftest"
+  ],
   "svg/text/reftests/textpath-shape-001-ref.svg": [
    "6206cb07df0e750a9a2c2e805e3ac2334309e493",
    "support"
@@ -407546,6 +408317,38 @@
    "621b7e7b6799868067acf594d0248e13747830ce",
    "reftest"
   ],
+  "svg/text/visualtests/text-inline-size-001-visual.svg": [
+   "3f324503faf0196fd9b76cba93c546c720e90f72",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-002-visual.svg": [
+   "8613452e81a6f73d902d5c1dad7a5c7909ccf3fe",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-003-visual.svg": [
+   "01d02938853ce250f0520393be3ae9cbefda03da",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-005-visual.svg": [
+   "170e7c5ee4e67887f13396774d987e52db6bb843",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-006-visual.svg": [
+   "7c5f9da911188f8a69c1aaa0a158a4f606b2953c",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-007-visual.svg": [
+   "408166290fa6573c8ce4f59a19d5564834df39c8",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-101-visual.svg": [
+   "5af35c0e9058fb4dd8a8e0ca4548bddca3466607",
+   "visual"
+  ],
+  "svg/text/visualtests/text-inline-size-201-visual.svg": [
+   "282f01657cde99a323dcabf54f0cdae31eb905fa",
+   "visual"
+  ],
   "svg/types/elements/SVGGeometryElement-rect-expected.txt": [
    "11b91f560c70bef8436895f6dbdba30de551863a",
    "support"
@@ -407706,6 +408509,14 @@
    "9e1f6ab25b99d75df4c885bf7cdaf9226d8c8bd4",
    "testharness"
   ],
+  "svg/types/scripted/event-handler-all-document-element-events-expected.txt": [
+   "2ab110e137c7348dbbf99f6ef2739c82596abaf4",
+   "support"
+  ],
+  "svg/types/scripted/event-handler-all-document-element-events.svg": [
+   "31761c9745e806bc527cd884c0559d454246d225",
+   "testharness"
+  ],
   "svg/types/scripted/resources/SVGLengthList-helper.js": [
    "e0cfabfa40e50ef2c25602563862caba72dd469e",
    "support"
@@ -409154,6 +409965,94 @@
    "acdf9d22c042ea3b2637c14b1576b4c8ffb4e97a",
    "support"
   ],
+  "wasm/jsapi/assertions.js": [
+   "4238583700450eb53b439a4be94ff645f15839f9",
+   "support"
+  ],
+  "wasm/jsapi/bad-imports.js": [
+   "62d79e19598c7851b2167bafa67e40240c75c9b7",
+   "support"
+  ],
+  "wasm/jsapi/constructor/instantiate-bad-imports.any.js": [
+   "3982f34f1f1519f6e68a59b8774af32f320ec24e",
+   "testharness"
+  ],
+  "wasm/jsapi/instance/constructor-bad-imports.any.js": [
+   "d9e24eb66edb923586d25d825d829b20c72911d0",
+   "testharness"
+  ],
+  "wasm/jsapi/instance/constructor.any.js": [
+   "9dedd497a1301a845b942c9d97592ff83ba3f0f4",
+   "testharness"
+  ],
+  "wasm/jsapi/interface.any-expected.txt": [
+   "a1723fbf04327441898ca6112811c22c3390ccbd",
+   "support"
+  ],
+  "wasm/jsapi/interface.any.js": [
+   "41f922170f108339a1e08e66a6c287c30c1dd3d6",
+   "testharness"
+  ],
+  "wasm/jsapi/interface.any.worker-expected.txt": [
+   "a1723fbf04327441898ca6112811c22c3390ccbd",
+   "support"
+  ],
+  "wasm/jsapi/memory/constructor.any-expected.txt": [
+   "497370aa424101b8f9d62640bad7a09923774fb3",
+   "support"
+  ],
+  "wasm/jsapi/memory/constructor.any.js": [
+   "caa0e9f80a446a25de82489b82cc03f660512b04",
+   "testharness"
+  ],
+  "wasm/jsapi/memory/constructor.any.worker-expected.txt": [
+   "497370aa424101b8f9d62640bad7a09923774fb3",
+   "support"
+  ],
+  "wasm/jsapi/module/constructor.any.js": [
+   "babdaa3936a89f9cad43f28ed3a5d66b9bd13dda",
+   "testharness"
+  ],
+  "wasm/jsapi/module/customSections.any-expected.txt": [
+   "62e01c278bc0b238519a38285a13d7f042289f26",
+   "support"
+  ],
+  "wasm/jsapi/module/customSections.any.js": [
+   "477202fdc215f2746dc4b247d0c0783b980edead",
+   "testharness"
+  ],
+  "wasm/jsapi/module/customSections.any.worker-expected.txt": [
+   "62e01c278bc0b238519a38285a13d7f042289f26",
+   "support"
+  ],
+  "wasm/jsapi/module/exports.any.js": [
+   "b066152fea1877694e1cabae12bf606b3c50dcd1",
+   "testharness"
+  ],
+  "wasm/jsapi/module/imports.any.js": [
+   "149d8661b3eb6ab68199574ce33ea9784103e517",
+   "testharness"
+  ],
+  "wasm/jsapi/table/constructor.any-expected.txt": [
+   "17c0c0892ac7feafe063b7877df31a1bace514f3",
+   "support"
+  ],
+  "wasm/jsapi/table/constructor.any.js": [
+   "351c99d612d5a07ce781fc5937ca3f2e82c6c3dd",
+   "testharness"
+  ],
+  "wasm/jsapi/table/constructor.any.worker-expected.txt": [
+   "17c0c0892ac7feafe063b7877df31a1bace514f3",
+   "support"
+  ],
+  "wasm/jsapi/wasm-constants.js": [
+   "6aba4f5fb4127cd56e1381bfb18204edde41abb2",
+   "support"
+  ],
+  "wasm/jsapi/wasm-module-builder.js": [
+   "d989de51de5092642de1ea9a1d2d9edc0e605031",
+   "support"
+  ],
   "wasm/resources/blank.html": [
    "0ddb4f1cf84729ed673295719ec58a3e5d600a12",
    "support"
@@ -409174,18 +410073,6 @@
    "d1b8ad09830985a5ce9ac0fe0f88b6d68eb7f012",
    "support"
   ],
-  "wasm/wasm_idb_worker.js": [
-   "3f8a0a4736251c836009b9281dd9a46d0b612235",
-   "support"
-  ],
-  "wasm/wasm_indexeddb_test.https.html": [
-   "2fcd9de0de5291930f331b25ee98e1c92490ab6a",
-   "testharness"
-  ],
-  "wasm/wasm_indexeddb_test.js": [
-   "e202fc90095365ce4d19e3ff3f2423e93d2f979b",
-   "support"
-  ],
   "wasm/wasm_local_iframe_test.html": [
    "e7b86a731b7cf7c122a1e37118cebce7342291fc",
    "testharness"
@@ -411726,6 +412613,10 @@
    "6f89b973ca7770bcb02f054c7f82326d003df8f3",
    "support"
   ],
+  "webrtc/RTCIceTransport-extension.https.html": [
+   "7124d5112bf71807172936c1a0a0b9fd4b3484cd",
+   "testharness"
+  ],
   "webrtc/RTCIceTransport.html": [
    "1b593c8ed167fd998195a2e2051bc489473f1bf4",
    "testharness"
@@ -411775,7 +412666,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-constructor-expected.txt": [
-   "690546c17c47d54083cb7735187db8d8a83b816a",
+   "9570ac1a99bcd14328d77804b8a78d74a391ec3c",
    "support"
   ],
   "webrtc/RTCPeerConnection-constructor.html": [
@@ -412255,7 +413146,7 @@
    "support"
   ],
   "webrtc/idlharness.https.window-expected.txt": [
-   "fc927276b7994269703a563bc0c90e9976da1b2b",
+   "488e238f27c07937793f97474e41f3cf50e29589",
    "support"
   ],
   "webrtc/idlharness.https.window.js": [
@@ -417530,8 +418421,12 @@
    "1f5a6dcb95464a46817c2b6ad09af6f64d53f128",
    "testharness"
   ],
+  "workers/modules/dedicated-worker-import-referrer-expected.txt": [
+   "849c2ffb7101b181e27bec999df756e4f8a3a992",
+   "support"
+  ],
   "workers/modules/dedicated-worker-import-referrer.html": [
-   "9495c1f58acf7062267fd59e682541950a659731",
+   "c41d89774837e4816b197e2b2b93bee23fc42cb4",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import.any.js": [
@@ -418138,6 +419033,10 @@
    "6e92613e720ac1fa1cdec91665cc1ca68a6e0bc8",
    "testharness"
   ],
+  "worklets/animation-worklet-referrer.https-expected.txt": [
+   "a4fdf44bc0ae720bce19cc1d5252908615514c12",
+   "support"
+  ],
   "worklets/animation-worklet-referrer.https.html": [
    "7c6e4a94815093e9353d184b877046ad7627bae9",
    "testharness"
@@ -418162,6 +419061,10 @@
    "33cf33b95b66020e10fef9515fce2956c27b75ba",
    "testharness"
   ],
+  "worklets/layout-worklet-referrer.https-expected.txt": [
+   "a4fdf44bc0ae720bce19cc1d5252908615514c12",
+   "support"
+  ],
   "worklets/layout-worklet-referrer.https.html": [
    "3de86e7b122d6e8403858279e280d7e6ea5af389",
    "testharness"
@@ -418182,6 +419085,10 @@
    "a1a5fe53abb00fe37c7688032038110a67f988ee",
    "testharness"
   ],
+  "worklets/paint-worklet-referrer.https-expected.txt": [
+   "a4fdf44bc0ae720bce19cc1d5252908615514c12",
+   "support"
+  ],
   "worklets/paint-worklet-referrer.https.html": [
    "86e7c0fe4de0764a7064ed22eef2b66ab09d4a62",
    "testharness"
@@ -418275,15 +419182,15 @@
    "support"
   ],
   "worklets/resources/referrer-checker.py": [
-   "3de9f5d0d90e5c360edd453a539cc2b83f45d42e",
+   "930c113063cfa5b0c2e5097761c82a443ff85ddf",
    "support"
   ],
   "worklets/resources/referrer-tests.js": [
-   "e072f492d6aa19866245b357a623c60ec3382c9a",
+   "bfa2e28259a44abf3aac6be528e51976c9ff782d",
    "support"
   ],
   "worklets/resources/referrer-window.html": [
-   "5900ef7037397bc3eb956b97c40cfd7a3a12c95f",
+   "adfb1c116fedb6396f970ed8072ee73edfc755fc",
    "support"
   ],
   "worklets/resources/service-worker-interception-tests.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/wasm-module-value.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/wasm-module-value.html
deleted file mode 100644
index 9fcfd780..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/wasm-module-value.html
+++ /dev/null
@@ -1,109 +0,0 @@
-<!doctype html>
-<meta charset="utf8">
-<meta name="timeout" content="long">
-<title>IndexedDB: WebAssembly module values</title>
-<link rel="help" href="https://w3c.github.io/IndexedDB/">
-<link rel="help" href="https://webassembly.github.io/spec/">
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support-promises.js"></script>
-<script>
-'use strict';
-
-// Binary representation for a WASM module that exports an "inc" function.
-//
-// This test covers storing WASM modules in IndexedDB. Its failure should only
-// be debugged if WASM specification tests pass. To this end, the test does not
-// use the WASM module builder helpers, trading off WASM debuggability in return
-// for having the WASM wire bytes listed explicitly in the test body. Having the
-// wire bytes spelled out can be helpful when debugging IndexedDB failures.
-let wasm_module_bytes = new Uint8Array([
-  0x00, 0x61, 0x73, 0x6d,  // Magic.
-  0x01, 0x00, 0x00, 0x00,  // Version.
-  0x01, 0x06, 0x01,              // Type section - 6 bytes, 1 entry
-  0x60, 0x01, 0x7f, 0x01, 0x7f,  // Type 0. Function: (i32) -> (i32)
-  0x03, 0x02, 0x01,   // Function section - 2 bytes, 1 entry
-  0x00,               // Function 0: Type 0
-  0x07, 0x07, 0x01,              // Export section - 7 bytes, 1 entry
-  0x03, 0x69, 0x6e, 0x63,        // Export 1. { name: "inc"
-  0x00, 0x00,                    //             desc: function 0 }
-  0x0a, 0x09, 0x01,  // Code section: 9 bytes, 1 entry
-  0x07, 0x00,        // Function 1: 7 code bytes, 0 locals
-  0x20, 0x00,        //   getlocal 0
-  0x41, 0x01,        //   i32.const 1
-  0x6a,              //   i32.add
-  0x0b,              //   end
-]);
-
-promise_test(async testCase => {
-  const wasm_module = await WebAssembly.compile(wasm_module_bytes.buffer);
-
-  const database = await createDatabase(testCase, (database, transaction) => {
-    const store = database.createObjectStore('store');
-    store.put(wasm_module, 'key1');
-  });
-
-  const result = await new Promise((resolve, reject) => {
-    const transaction = database.transaction(['store'], 'readonly');
-    const store = transaction.objectStore('store');
-    const request = store.get('key1');
-    request.onsuccess = (event) => resolve(event.target.result);
-    request.onerror = (event) => reject(event.target.error);
-  });
-
-  database.close();
-
-  const instance = await WebAssembly.instantiate(result);
-  assert_equals(
-      instance.exports['inc'](42), 43, 'inc should increment its argument');
-}, 'WebAssembly module as an IndexedDB value');
-
-promise_test(async testCase => {
-  const wasm_module = await WebAssembly.compile(wasm_module_bytes.buffer);
-
-  const database = await createDatabase(testCase, (database, transaction) => {
-    const store = database.createObjectStore('store');
-    store.put({ module: wasm_module }, 'key1');
-  });
-
-  const result = await new Promise((resolve, reject) => {
-    const transaction = database.transaction(['store'], 'readonly');
-    const store = transaction.objectStore('store');
-    const request = store.get('key1');
-    request.onsuccess = (event) => resolve(event.target.result);
-    request.onerror = (event) => reject(event.target.error);
-  });
-
-  database.close();
-
-  const instance = await WebAssembly.instantiate(result.module);
-  assert_equals(
-      instance.exports['inc'](42), 43, 'inc should increment its argument');
-}, 'WebAssembly module in a JavaScript object IndexedDB value');
-
-promise_test(async testCase => {
-  const wasm_module = await WebAssembly.compile(wasm_module_bytes.buffer);
-
-  const database = await createDatabase(testCase, (database, transaction) => {
-    const store = database.createObjectStore('store', { keyPath: 'key' });
-    store.put({ key: 'key1', module: wasm_module });
-  });
-
-  const result = await new Promise((resolve, reject) => {
-    const transaction = database.transaction(['store'], 'readonly');
-    const store = transaction.objectStore('store');
-    const request = store.get('key1');
-    request.onsuccess = (event) => resolve(event.target.result);
-    request.onerror = (event) => reject(event.target.error);
-  });
-
-  database.close();
-
-  assert_equals('key1', result.key);
-  const instance = await WebAssembly.instantiate(result.module);
-  assert_equals(
-      instance.exports['inc'](42), 43, 'inc should increment its argument');
-}, 'WebAssembly module in an IndexedDB value with an inline key');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any-expected.txt
new file mode 100644
index 0000000..79ea026
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any-expected.txt
@@ -0,0 +1,62 @@
+This is a testharness.js-based test.
+PASS background-fetch interfaces
+PASS Partial interface ServiceWorkerGlobalScope: original interface defined
+PASS Partial interface ServiceWorkerRegistration: original interface defined
+PASS BackgroundFetchManager interface: existence and properties of interface object
+PASS BackgroundFetchManager interface object length
+PASS BackgroundFetchManager interface object name
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchManager interface: operation fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions)
+PASS BackgroundFetchManager interface: operation get(DOMString)
+PASS BackgroundFetchManager interface: operation getIds()
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
+PASS BackgroundFetchRegistration interface object length
+PASS BackgroundFetchRegistration interface object name
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchRegistration interface: attribute id
+PASS BackgroundFetchRegistration interface: attribute uploadTotal
+PASS BackgroundFetchRegistration interface: attribute uploaded
+PASS BackgroundFetchRegistration interface: attribute downloadTotal
+PASS BackgroundFetchRegistration interface: attribute downloaded
+FAIL BackgroundFetchRegistration interface: attribute activeFetches assert_true: The prototype object must have a property "activeFetches" expected true got false
+PASS BackgroundFetchRegistration interface: attribute onprogress
+PASS BackgroundFetchRegistration interface: operation abort()
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation match(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation matchAll(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation values() assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+PASS BackgroundFetchFetch interface: existence and properties of interface object
+PASS BackgroundFetchFetch interface object length
+PASS BackgroundFetchFetch interface object name
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchFetch interface: attribute request
+PASS BackgroundFetchEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetches interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetch interface: existence and properties of interface object
+PASS BackgroundFetchUpdateEvent interface: existence and properties of interface object
+PASS BackgroundFetchClickEvent interface: existence and properties of interface object
+PASS ServiceWorkerRegistration interface: attribute backgroundFetch
+PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
+PASS WorkerGlobalScope interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.any.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.any.js
rename to third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.sharedworker-expected.txt
new file mode 100644
index 0000000..a7a6e7dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.sharedworker-expected.txt
@@ -0,0 +1,61 @@
+This is a testharness.js-based test.
+PASS background-fetch interfaces
+PASS Partial interface ServiceWorkerGlobalScope: original interface defined
+PASS Partial interface ServiceWorkerRegistration: original interface defined
+PASS BackgroundFetchManager interface: existence and properties of interface object
+PASS BackgroundFetchManager interface object length
+PASS BackgroundFetchManager interface object name
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchManager interface: operation fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions)
+PASS BackgroundFetchManager interface: operation get(DOMString)
+PASS BackgroundFetchManager interface: operation getIds()
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
+PASS BackgroundFetchRegistration interface object length
+PASS BackgroundFetchRegistration interface object name
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchRegistration interface: attribute id
+PASS BackgroundFetchRegistration interface: attribute uploadTotal
+PASS BackgroundFetchRegistration interface: attribute uploaded
+PASS BackgroundFetchRegistration interface: attribute downloadTotal
+PASS BackgroundFetchRegistration interface: attribute downloaded
+FAIL BackgroundFetchRegistration interface: attribute activeFetches assert_true: The prototype object must have a property "activeFetches" expected true got false
+PASS BackgroundFetchRegistration interface: attribute onprogress
+PASS BackgroundFetchRegistration interface: operation abort()
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation match(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation matchAll(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation values() assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+PASS BackgroundFetchFetch interface: existence and properties of interface object
+PASS BackgroundFetchFetch interface object length
+PASS BackgroundFetchFetch interface object name
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchFetch interface: attribute request
+PASS BackgroundFetchEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetches interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetch interface: existence and properties of interface object
+PASS BackgroundFetchUpdateEvent interface: existence and properties of interface object
+PASS BackgroundFetchClickEvent interface: existence and properties of interface object
+PASS ServiceWorkerRegistration interface: attribute backgroundFetch
+PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.worker-expected.txt
new file mode 100644
index 0000000..a7a6e7dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/idlharness.https.any.worker-expected.txt
@@ -0,0 +1,61 @@
+This is a testharness.js-based test.
+PASS background-fetch interfaces
+PASS Partial interface ServiceWorkerGlobalScope: original interface defined
+PASS Partial interface ServiceWorkerRegistration: original interface defined
+PASS BackgroundFetchManager interface: existence and properties of interface object
+PASS BackgroundFetchManager interface object length
+PASS BackgroundFetchManager interface object name
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchManager interface: operation fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions)
+PASS BackgroundFetchManager interface: operation get(DOMString)
+PASS BackgroundFetchManager interface: operation getIds()
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
+PASS BackgroundFetchRegistration interface object length
+PASS BackgroundFetchRegistration interface object name
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchRegistration interface: attribute id
+PASS BackgroundFetchRegistration interface: attribute uploadTotal
+PASS BackgroundFetchRegistration interface: attribute uploaded
+PASS BackgroundFetchRegistration interface: attribute downloadTotal
+PASS BackgroundFetchRegistration interface: attribute downloaded
+FAIL BackgroundFetchRegistration interface: attribute activeFetches assert_true: The prototype object must have a property "activeFetches" expected true got false
+PASS BackgroundFetchRegistration interface: attribute onprogress
+PASS BackgroundFetchRegistration interface: operation abort()
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation match(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation matchAll(RequestInfo, CacheQueryOptions) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation values() assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+PASS BackgroundFetchFetch interface: existence and properties of interface object
+PASS BackgroundFetchFetch interface object length
+PASS BackgroundFetchFetch interface object name
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchFetch interface: attribute request
+PASS BackgroundFetchEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetches interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetch interface: existence and properties of interface object
+PASS BackgroundFetchUpdateEvent interface: existence and properties of interface object
+PASS BackgroundFetchClickEvent interface: existence and properties of interface object
+PASS ServiceWorkerRegistration interface: attribute backgroundFetch
+PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-layout-properties.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-layout-properties.html
index 249c4a7..fcc2ce3b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-layout-properties.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/grid-layout-properties.html
@@ -94,7 +94,7 @@
         '<line-names>': ['[a] auto [b] auto [c]', '[a] 50px [b] 50px [c] 50px'],
         '<track-size>.auto': ['auto', '50px 50px 50px'],
         '<track-size>.<track-breadth>.<length>': ['100px', '100px 50px 50px'],
-        '<track-size>.<track-breadth>.<percentage>': ['100%', '50px 50px 50px'],
+        '<track-size>.<track-breadth>.<percentage>': ['100%', '150px 50px 50px'],
         '<track-size>.<track-breadth>.<flex>': ['1fr', '50px 50px 50px'],
         '<track-size>.<track-breadth>.min-content': ['min-content', '50px 50px 50px'],
         '<track-size>.<track-breadth>.max-content': ['max-content', '50px 50px 50px'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html
new file mode 100644
index 0000000..d1af28ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: overflow-wrap: break-word and intrinsic sizing</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property">
+<meta name="flags" content="ahem">
+<link rel="match" href="reference/overflow-wrap-min-content-size-003-ref.html">
+<meta name="assert" content="overflow-wrap:break-word breaks at edge of inline elements.">
+<style>
+#wrapper {
+  width: 0px;
+  font: 16px / 1 Ahem;
+  overflow-wrap: break-word;
+  color: green;
+}
+#test {
+  float: left;
+}
+#reference {
+  position: absolute;
+  width: 16px;
+  height: 128px;
+  background: red;
+  z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a vertical green bar below.
+<div id="wrapper">
+  <div id="reference"></div>
+  <div id="test"><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html
new file mode 100644
index 0000000..a71b3a34d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test reference</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+<meta name="flags" content="ahem">
+<style>
+#wrapper {
+  width: 0px;
+  font: 16px / 1 Ahem;
+  color: green;
+}
+#test {
+  float: left;
+}
+#reference {
+  position: absolute;
+  width: 16px;
+  height: 128px;
+  background: red;
+  z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a vertical green bar below.
+<div id="wrapper">
+  <div id="reference"></div>
+  <div id="test">X<br>X<br>X<br>X<br>X<br>X<br>X<br>X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
index fbc962c5..18388c8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 377 tests; 322 PASS, 55 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 377 tests; 323 PASS, 54 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Partial interface Document: original interface defined
 PASS Partial interface Window: original interface defined
@@ -38,7 +38,7 @@
 PASS StyleSheet interface: attribute title
 PASS StyleSheet interface: attribute media
 PASS StyleSheet interface: attribute disabled
-FAIL CSSStyleSheet interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function () { [native code] }" did not throw
+PASS CSSStyleSheet interface: existence and properties of interface object
 PASS CSSStyleSheet interface object length
 PASS CSSStyleSheet interface object name
 PASS CSSStyleSheet interface: existence and properties of interface prototype object
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/historical-expected.txt
index fdfba77..2c0959b7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/historical-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/historical-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 74 tests; 70 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 75 tests; 71 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Historical DOM features must be removed: DOMConfiguration
 PASS Historical DOM features must be removed: DOMCursor
 FAIL Historical DOM features must be removed: DOMError assert_equals: expected (undefined) undefined but got (function) function "function DOMError() { [native code] }"
@@ -34,6 +34,7 @@
 PASS Historical DOM features must be removed: cssElementMap
 PASS Historical DOM features must be removed: async
 PASS document.load
+PASS XMLDocument.load
 PASS DOMImplementation.getFeature() must be nuked.
 PASS Historical DOM features must be removed: schemaTypeInfo
 PASS Historical DOM features must be removed: setIdAttribute
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/historical.html b/third_party/WebKit/LayoutTests/external/wpt/dom/historical.html
index b45bebf..921fa07b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/historical.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/historical.html
@@ -67,6 +67,12 @@
 }, "document.load");
 
 test(function() {
+  // https://github.com/whatwg/html/commit/523f7a8773d2ab8a1eb0da6510651e8c5d2a7531
+  var doc = document.implementation.createDocument(null, null, null);
+  assert_false("load" in doc);
+}, "XMLDocument.load");
+
+test(function() {
   assert_equals(document.implementation["getFeature"], undefined)
 }, "DOMImplementation.getFeature() must be nuked.")
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.sub.html b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.sub.html
rename to third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.html
index 8e960110..242def1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Document-URL.html
@@ -12,7 +12,7 @@
   this.add_cleanup(function() { document.body.removeChild(iframe); });
   iframe.onload = this.step_func_done(function() {
     assert_equals(iframe.contentDocument.URL,
-                  "http://{{host}}:{{ports[http][0]}}/common/blank.html");
+                  location.origin + "/common/blank.html");
   });
 })
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/rootNode.html b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/rootNode.html
index 66343e7..784831d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/rootNode.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/rootNode.html
@@ -11,6 +11,20 @@
 <script>
 
 test(function () {
+    var shadowHost = document.createElement('div');
+    document.body.appendChild(shadowHost);
+
+    var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+    shadowRoot.innerHTML = '<div class="shadowChild">content</div>';
+
+    var shadowChild = shadowRoot.querySelector('.shadowChild');
+    assert_equals(shadowChild.getRootNode({composed: true}), document, "getRootNode() must return context object's shadow-including root if options's composed is true");
+    assert_equals(shadowChild.getRootNode({composed: false}), shadowRoot, "getRootNode() must return context object's root if options's composed is false");
+    assert_equals(shadowChild.getRootNode(), shadowRoot, "getRootNode() must return context object's root if options's composed is default false");
+
+}, "getRootNode() must return context object's shadow-including root if options's composed is true, and context object's root otherwise");
+
+test(function () {
     var element = document.createElement('div');
     assert_equals(element.getRootNode(), element, 'getRootNode() on an element without a parent must return the element itself');
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-open-noopener.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
index 7d1d430c..52560537 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
@@ -6,6 +6,7 @@
 <meta name="variant" content="?_self">
 <meta name="variant" content="?_parent">
 <meta name="variant" content="?_top">
+<meta name=timeout content=long>
 
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub-expected.txt
deleted file mode 100644
index 755a2ea7..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-FAIL The 'href' attribute of the 'a' element assert_equals: The 'href' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'href' attribute of the 'link' element assert_equals: The 'href' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'href' attribute of the 'area' element assert_equals: The 'href' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'cite' attribute of the 'q' element assert_equals: The 'cite' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'cite' attribute of the 'blockquote' element assert_equals: The 'cite' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'cite' attribute of the 'ins' element assert_equals: The 'cite' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'cite' attribute of the 'del' element assert_equals: The 'cite' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'img' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'embed' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'video' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'iframe' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'script' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'source' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'src' attribute of the 'track' element assert_equals: The 'src' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'action' attribute of the 'form' element assert_equals: The 'action' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'data' attribute of the 'object' element assert_equals: The 'data' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL The 'formaction' attribute of the 'button' element assert_equals: The 'formAction' attribute is incorrect. expected "http://www.web-platform.test:8001/test.txt" but got "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-FAIL Change the base URL must effect the descendant elements only assert_not_equals: The inner element must be effected. got disallowed value "http://web-platform.test:8001/html/infrastructure/urls/dynamic-changes-to-base-urls/test.txt"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html
new file mode 100644
index 0000000..ce65f392
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>HTML Test: Dynamic changes to base URLs</title>
+<link rel="author" title="Intel" href="http://www.intel.com/"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dynamic-changes-to-base-urls" />
+<base href="" id="base">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="div" style="display:none"></div>
+<script>
+      var div = document.getElementById("div"),
+          base = document.getElementById("base"),
+          url =  document.location.href;
+
+      var testData = [
+        {elements: ["a", "link", "area"], set: "href", get: "href"},
+        {elements: ["q", "blockquote", "ins", "del"], set: "cite", get: "cite"},
+        {elements: ["audio", "input", "img", "embed", "video", "iframe", "script", "source", "track"], set: "src", get: "src"},
+        {elements: ["form"], set: "action", get: "action"},
+        {elements: ["object"], set: "data", get: "data"},
+        {elements: ["button"], set: "formAction", get: "formAction"}
+      ];
+
+      for (var i in testData) {
+        var item = testData[i];
+        for (var j in item.elements) {
+          test(function () {
+            var ele = document.createElement(item.elements[j]);
+
+            ele.setAttribute(item.set, "test.txt");
+            div.appendChild(ele);
+
+            base.setAttribute("href", "");
+            assert_equals(ele[item.get], url.substr(0, url.lastIndexOf("/")) +"/test.txt", "The '" + item.get + "' attribute is incorrect.");
+            base.setAttribute("href", "http://{{domains[www]}}:{{ports[http][0]}}");
+            assert_equals(ele[item.get], "http://{{domains[www]}}:{{ports[http][0]}}/test.txt", "The '" + item.get + "' attribute is incorrect.");
+          }, "The '" + item.set + "' attribute of the '" + item.elements[j] + "' element");
+        }
+      }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml b/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml
similarity index 74%
rename from third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml
rename to third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml
index 7302ed6..1be7a7c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/dynamic-urls.sub.xhtml
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/urls/dynamic-changes-to-base-urls/historical.sub.xhtml
@@ -2,9 +2,9 @@
 <!DOCTYPE html>
 <html id="h" xmlns="http://www.w3.org/1999/xhtml" xml:base="">
   <head>
-    <title>HTML Test: Dynamic changes to base URLs</title>
+    <title>Historical xml:base must be removed</title>
     <link rel="author" title="Intel" href="http://www.intel.com/"/>
-    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dynamic-changes-to-base-urls" />
+    <link rel="help" href="https://github.com/whatwg/html/pull/84/files" />
     <script src="/resources/testharness.js" id="s1"></script>
     <script src="/resources/testharnessreport.js"></script>
   </head>
@@ -20,7 +20,7 @@
       var testData = [
         {elements: ["a", "link", "area"], set: "href", get: "href"},
         {elements: ["q", "blockquote", "ins", "del"], set: "cite", get: "cite"},
-        {elements: ["img", "embed", "video", "iframe", "script", "source", "track"], set: "src", get: "src"},
+        {elements: ["audio", "input", "img", "embed", "video", "iframe", "script", "source", "track"], set: "src", get: "src"},
         {elements: ["form"], set: "action", get: "action"},
         {elements: ["object"], set: "data", get: "data"},
         {elements: ["button"], set: "formaction", get: "formAction"}
@@ -38,7 +38,7 @@
             html.setAttribute("xml:base", "");
             assert_equals(ele[item.get], url.substr(0, url.lastIndexOf("/")) +"/test.txt", "The '" + item.get + "' attribute is incorrect.");
             html.setAttribute("xml:base", "http://{{domains[www]}}:{{ports[http][0]}}");
-            assert_equals(ele[item.get], "http://{{domains[www]}}:{{ports[http][0]}}/test.txt", "The '" + item.get + "' attribute is incorrect.");
+            assert_not_equals(ele[item.get], "http://{{domains[www]}}:{{ports[http][0]}}/test.txt", "The '" + item.get + "' attribute is incorrect.");
           }, "The '" + item.set + "' attribute of the '" + item.elements[j] + "' element");
         }
       }
@@ -50,9 +50,9 @@
 
         div.setAttribute("xml:base", "http://{{domains[www2]}}:{{ports[http][0]}}");
         assert_equals(s1.src, val1, "The outer element must not be effected.");
-        assert_not_equals(div.firstChild.href, val2, "The inner element must be effected.");
-        assert_equals(div.firstChild.href, "http://{{domains[www2]}}:{{ports[http][0]}}/test.txt");
-      }, "Change the base URL must effect the descendant elements only");
+        assert_equals(div.firstChild.href, val2, "The inner element must be effected.");
+        assert_not_equals(div.firstChild.href, "http://{{domains[www2]}}:{{ports[http][0]}}/test.txt");
+      }, "Change the base URL must not effect the descendant elements");
       ]]>
     </script>
   </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html
new file mode 100644
index 0000000..a37da3c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-face.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>font face</title>
+<link rel="help" href="https://html.spec.whatwg.org/#the-font-element-text-decoration-color-quirk">
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+const types = ["serif", "sans-serif", "cursive", "fantasy", "monospace"];
+for (let type of types) {
+  test(() => {
+    let elem = document.createElement("font");
+    elem.setAttribute("face", type);
+    document.body.appendChild(elem);
+    let exp_type = window.getComputedStyle(elem, null).getPropertyValue("font-family");
+    assert_equals(exp_type, type);
+  }, `font face attribute ${type} is correct`);
+}
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html
new file mode 100644
index 0000000..8e8b9f2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/font-element-text-decoration-color/font-size.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>font size</title>
+<link rel="help" href="https://html.spec.whatwg.org/#the-font-element-text-decoration-color-quirk">
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+
+<script>
+
+const modes = ["", "+", "-"];
+const values = ["0", "1", "2", "3", "4", "5", "6", "7", "8"];
+const rels = [
+  ["1", "x-small"],
+  ["2", "small"],
+  ["3", "medium"],
+  ["4", "large"],
+  ["5", "x-large"],
+  ["6", "xx-large"],
+  ["7", "xxx-large"]
+];
+let results = getCSSFontSize(rels);
+
+function cal(n) {
+  //If value is greater than 7, let it be 7
+  //If value is less than 1, let it be 1
+  return n > 7 ? 7 : (n < 1 ? 1 : n);
+}
+
+function getRealInput(mode, value) {
+  switch(mode) {
+    case "+":
+      //If mode is relative-plus, then increment value by 3
+      return cal(3 + parseInt(value));
+    case "-":
+      // If mode is relative-minus, then let value be the result of subtracting value from 3
+      return cal(3 - parseInt(value));
+    default:
+      return cal(parseInt(value));
+  }
+}
+
+function getCSSFontSize(rels) {
+  let results = {};
+  for (let [key, value] of rels) {
+    if (key == "7") {
+      //The 'xxx-large' value is a non-CSS value used here to indicate a font size 50% larger than 'xx-large'.
+      let size = parseInt(results["6"]) * 1.5;
+      results[key] = size.toString();
+      return results;
+    }
+    let elem = document.createElement("span");
+    document.body.appendChild(elem);
+    elem.setAttribute("style", `font-size: ${value}`);
+    let exp_size = window.getComputedStyle(elem, null).getPropertyValue("font-size");
+    results[key] = exp_size.slice(0, -2);
+  }
+  return results;
+}
+
+for (let mode of modes) {
+  for (let value of values) {
+    test(() => {
+      let size = getRealInput(mode, value);
+      let elem = document.createElement("font");
+      elem.setAttribute("size", `${mode}${value}`);
+      document.body.appendChild(elem);
+      let exp_size = window.getComputedStyle(elem, null).getPropertyValue("font-size");
+      assert_equals(exp_size.slice(0, -2), results[size]);
+    }, `font size attribute ${mode}${value} is correct`);
+  }
+}
+
+test(() => {
+  let span_elem = document.createElement("span");
+  document.body.appendChild(span_elem);
+  span_elem.setAttribute("style", "font-size: medium");
+  let span_size = window.getComputedStyle(span_elem, null).getPropertyValue("font-size");
+
+  let font_elem = document.createElement("font");
+  document.body.appendChild(font_elem);
+  let font_size = window.getComputedStyle(font_elem, null).getPropertyValue("font-size");
+  assert_equals(font_size, span_size);
+
+  font_elem.setAttribute("size", "");
+  font_size = window.getComputedStyle(font_elem, null).getPropertyValue("font-size");
+  assert_equals(font_size, span_size);
+
+  font_elem.setAttribute("size", " ");
+  font_size = window.getComputedStyle(font_elem, null).getPropertyValue("font-size");
+  assert_equals(font_size, span_size);
+
+  font_elem.setAttribute("size", " 3");
+  font_size = window.getComputedStyle(font_elem, null).getPropertyValue("font-size");
+  assert_equals(font_size, span_size);
+
+  font_elem.setAttribute("size", "3");
+  font_size = window.getComputedStyle(font_elem, null).getPropertyValue("font-size");
+  assert_equals(font_size, span_size);
+}, "font size default value is 3");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.https.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.html
rename to third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol.https.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/initial-observation-with-threshold.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/initial-observation-with-threshold.html
new file mode 100644
index 0000000..d677f0ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/initial-observation-with-threshold.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+.spacer {
+  height: calc(100vh + 100px);
+}
+#root {
+  display: inline-block;
+  overflow-y: scroll;
+  height: 240px;
+  border: 3px solid black;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  margin: 200px 0 0 0;
+  background-color: green;
+}
+</style>
+
+<div id="root">
+  <div id="target"></div>
+</div>
+
+<script>
+var entries = [];
+var root, target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  root = document.getElementById("root");
+  assert_true(!!root, "root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, { root: root, threshold: [0.5] });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF");
+}, "First observation with a threshold.");
+
+function step0() {
+  root.scrollTop = 20;
+  runTestCycle(step1, "root.scrollTop = 20");
+  checkLastEntry(entries, 0, [ 11, 111, 211, 311, 11, 111, 211, 251, 11, 111, 11, 251, false]);
+}
+
+function step1() {
+  checkLastEntry(entries, 1, [ 11, 111, 191, 291, 11, 111, 191, 251, 11, 111, 11, 251, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/notifications/idlharness.any.js b/third_party/WebKit/LayoutTests/external/wpt/notifications/idlharness.https.any.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/notifications/idlharness.any.js
rename to third_party/WebKit/LayoutTests/external/wpt/notifications/idlharness.https.any.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
index d1f693a..522411b5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
@@ -15,7 +15,10 @@
   explicit_timeout: true,
 });
 const basicCard = Object.freeze({ supportedMethods: "basic-card" });
-const defaultMethods = Object.freeze([basicCard]);
+const applePay = Object.freeze({
+  supportedMethods: "https://apple.com/apple-pay",
+});
+const defaultMethods = Object.freeze([basicCard, applePay]);
 const defaultDetails = Object.freeze({
   total: {
     label: "Total",
@@ -26,53 +29,53 @@
   },
 });
 
-window.onload = async () => {
-  promise_test(async t => {
-    // request is in "created" state
+promise_test(async t => {
+  // request is in "created" state
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  await promise_rejects(t, "InvalidStateError", request.abort());
+}, `Throws if the promise [[state]] is not "interactive"`);
+
+promise_test(async t => {
+  return test_driver.bless("show payment request", async () => {
+    const request = new PaymentRequest(defaultMethods, defaultDetails);
+    const acceptPromise = request.show();
+    try {
+      await request.abort();
+    } catch (err) {
+      assert_unreached("Unexpected promise rejection: " + err.message);
+    }
+    await promise_rejects(t, "AbortError", acceptPromise);
+    // As request is now "closed", trying to show it will fail
+    await promise_rejects(t, "InvalidStateError", request.show());
+  });
+});
+
+promise_test(async t => {
+  return test_driver.bless("show payment request", async () => {
+    // request is in "created" state.
     const request = new PaymentRequest(defaultMethods, defaultDetails);
     await promise_rejects(t, "InvalidStateError", request.abort());
-  }, `Throws if the promise [[state]] is not "interactive"`);
-
-  const button = document.getElementById("button");
-
-  promise_test(async t => {
-    button.onclick = async () => {
-      const request = new PaymentRequest(defaultMethods, defaultDetails);
-      const acceptPromise = request.show();
-      try {
-        await request.abort();
-      } catch (err) {
-        assert_unreached("Unexpected promise rejection: " + err.message);
-      }
-      await promise_rejects(t, "AbortError", acceptPromise);
-      // As request is now "closed", trying to show it will fail
-      await promise_rejects(t, "InvalidStateError", request.show());
-    };
-    await test_driver.click(button);
+    // Call it again, for good measure.
+    await promise_rejects(t, "InvalidStateError", request.abort());
+    // The request's state is "created", so let's show it
+    // which changes the state to "interactive.".
+    const acceptPromise = request.show();
+    // Let's set request the state to "closed" by calling .abort()
+    try {
+      await request.abort();
+    } catch (err) {
+      assert_unreached("Unexpected promise rejection: " + err.message);
+    }
+    // The request is now "closed", so...
+    await promise_rejects(t, "InvalidStateError", request.abort());
+    await promise_rejects(t, "AbortError", acceptPromise);
   });
+});
 
-  promise_test(async t => {
-    button.onclick = async () => {
-      // request is in "created" state.
-      const request = new PaymentRequest(defaultMethods, defaultDetails);
-      await promise_rejects(t, "InvalidStateError", request.abort());
-      // Call it again, for good measure.
-      await promise_rejects(t, "InvalidStateError", request.abort());
-      // The request's state is "created", so let's show it
-      // which changes the state to "interactive.".
-      const acceptPromise = request.show();
-      // Let's set request the state to "closed" by calling .abort()
-      try {
-        await request.abort();
-      } catch (err) {
-        assert_unreached("Unexpected promise rejection: " + err.message);
-      }
-      // The request is now "closed", so...
-      await promise_rejects(t, "InvalidStateError", request.abort());
-      await promise_rejects(t, "AbortError", acceptPromise);
-    };
-    await test_driver.click(button);
-  });
-};
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  const promises = new Set([request.abort(), request.abort(), request.abort()]);
+  assert_equals(promises.size, 3, "Must have three unique objects");
+}, "Calling abort() multiple times is always a new object.");
 </script>
-<button id="button"></button>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
index 9269b3a3..0f09114 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https-expected.txt
@@ -1,10 +1,4 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Request failed
-FAIL If request.[[state]] is "created", then return a promise that resolves to true for known method. assert_equals: if it throws, then it must be a NotAllowedError. expected "NotAllowedError" but got "UnknownError"
-FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If payment method identifier and serialized parts are supported, resolve promise with true. promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If payment method identifier is unknown, resolve promise with false. assert_equals: if it throws, then it must be a NotAllowedError. expected "NotAllowedError" but got "UnknownError"
-FAIL Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException. assert_equals: if it throws, then it must be a NotAllowedError. expected "NotAllowedError" but got "UnknownError"
+FAIL Tests for PaymentRequest.canMakePayment() method Uncaught TypeError: Cannot set property 'click' of undefined
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-manual.https.html
rename to third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
index 5ea639b..617bd6e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-manual.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
@@ -4,12 +4,9 @@
 <link rel="help" href="https://w3c.github.io/browser-payment-api/#show-method">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src='/resources/testdriver-vendor.js'></script>
+<script src="/resources/testdriver.js"></script>
 <script>
-setup({
-  explicit_done: true,
-  explicit_timeout: true,
-});
-
 const basicCard = Object.freeze({ supportedMethods: "basic-card" });
 const defaultMethods = Object.freeze([basicCard]);
 const defaultDetails = Object.freeze({
@@ -124,14 +121,10 @@
   }
 }, `Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.`);
 
-function manualTest1(elem){
-  elem.disabled = true;
-
-  // NB: request.show has to be called outside of promise_test to ensure the
-  // user's click is still visible to PaymentRequest.show.
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = request.show(); // Sets state to "interactive"
-  promise_test(async t => {
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
+    const request = new PaymentRequest(defaultMethods, defaultDetails);
+    const acceptPromise = request.show(); // Sets state to "interactive"
     const canMakePaymentPromise = request.canMakePayment();
     try {
       const result = await canMakePaymentPromise;
@@ -147,18 +140,14 @@
     }
     // The state should be "closed"
     await promise_rejects(t, "InvalidStateError", request.canMakePayment());
-  }, elem.textContent.trim());
-}
+  });
+}, 'If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.');
 
-function manualTest2(elem){
-  elem.disabled = true;
-
-  // See above for why it's important for these lines to be outside of
-  // promise_test.
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = request.show(); // The state is now "interactive"
-  acceptPromise.catch(() => {}); // no-op, just to silence unhandled rejection in devtools.
-  promise_test(async t => {
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
+    const request = new PaymentRequest(defaultMethods, defaultDetails);
+    const acceptPromise = request.show(); // The state is now "interactive"
+    acceptPromise.catch(() => {}); // no-op, just to silence unhandled rejection in devtools.
     await request.abort(); // The state is now "closed"
     await promise_rejects(t, "InvalidStateError", request.canMakePayment());
     try {
@@ -174,28 +163,23 @@
         "must be an InvalidStateError."
       );
     }
-  }, elem.textContent.trim());
-  done();
-}
+  });
+}, 'If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.');
+
+test(() => {
+  const request = new PaymentRequest(
+    [{ supportedMethods: "basic-card" }],
+    defaultDetails
+  );
+  const promises = new Set([
+    request.canMakePayment(),
+    request.canMakePayment(),
+    request.canMakePayment(),
+  ]);
+  assert_equals(promises.size, 3, "Must have three unique objects");
+}, "Calling canMakePayment() multiple times is always a new object.");
 </script>
 
-<h2>Tests for PaymentRequest.canMakePayment() method</h2>
-<p>
-  Click on each button in sequence from top to bottom without refreshing the page.
-  No payment sheet will be shown, but the tests will run in the background.
-</p>
-<ol>
-  <li>
-    <button onclick="manualTest1(this)">
-      If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.
-    </button>
-  </li>
-  <li>
-    <button onclick="manualTest2(this)">
-      If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.
-    </button>
-  </li>
-</ol>
 <small>
   If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
   and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
index 38ab786b..c6e69d4c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
@@ -6,13 +6,11 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<button id="button"></button>
 <script>
-'use strict';
-const button = document.getElementById("button");
+"use strict";
 const defaultMethods = Object.freeze([
   { supportedMethods: "basic-card" },
-  { supportedMethods: "https://apple.com/apple-pay" }
+  { supportedMethods: "https://apple.com/apple-pay" },
 ]);
 
 const defaultDetails = Object.freeze({
@@ -31,19 +29,18 @@
   await promise_rejects(t, "SecurityError", acceptPromise);
 }, `Calling show() without being triggered by user interaction throws`);
 
-promise_test(async t => {
-  button.onclick = async () => {
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
     const request = new PaymentRequest(defaultMethods, defaultDetails);
     const acceptPromise = request.show(); // Sets state to "interactive"
     await promise_rejects(t, "InvalidStateError", request.show());
     await request.abort();
     await promise_rejects(t, "AbortError", acceptPromise);
-  };
-  await test_driver.click(button);
+  });
 }, "Throws if the promise [[state]] is not 'created'.");
 
-promise_test(async t => {
-  button.onclick = async () => {
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
     const request1 = new PaymentRequest(defaultMethods, defaultDetails);
     const request2 = new PaymentRequest(defaultMethods, defaultDetails);
     const acceptPromise1 = request1.show();
@@ -51,19 +48,33 @@
     await promise_rejects(t, "AbortError", acceptPromise2);
     await request1.abort();
     await promise_rejects(t, "AbortError", acceptPromise1);
-  };
-  await test_driver.click(button);
+  });
 }, `If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException.`);
 
-promise_test(async t => {
-  button.onclick = async () => {
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
     const request = new PaymentRequest(
       [{ supportedMethods: "this-is-not-supported" }],
       defaultDetails
     );
     const acceptPromise = request.show();
     await promise_rejects(t, "NotSupportedError", acceptPromise);
-  };
-  await test_driver.click(button);
+  });
 }, `If payment method consultation produces no supported method of payment, then return a promise rejected with a "NotSupportedError" DOMException.`);
+
+promise_test(t => {
+  return test_driver.bless("show payment request", async () => {
+    const request = new PaymentRequest(
+      [{ supportedMethods: "basic-card" }],
+      defaultDetails
+    );
+    const promises = new Set([request.show(), request.show(), request.show()]);
+    await request.abort();
+    assert_equals(promises.size, 3, "Must have three unique objects");
+  });
+}, "Calling show() multiple times is always a new object.");
 </script>
+<small>
+  If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
+  and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
+</small>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/complete-method-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/complete-method-manual.https.html
index 64d5c53..a9da9ee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/complete-method-manual.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/complete-method-manual.https.html
@@ -14,12 +14,13 @@
   promise_test(async t => {
     try {
       // We .complete() as normal, using the passed test value
-      const promise = response.complete(result);
-      assert_true(promise instanceof Promise, "returns a promise");
+      const completePromise = response.complete(result);
+      assert_true(completePromise instanceof Promise, "returns a promise");
       // Immediately calling complete() again yields a rejected promise.
-      await promise_rejects(t, "InvalidStateError", response.complete(result));
+      const invalidComplete = response.complete(result);
+      await promise_rejects(t, "InvalidStateError", invalidComplete);
       // but the original promise is unaffected
-      const returnedValue = await promise;
+      const returnedValue = await completePromise;
       assert_equals(
         returnedValue,
         undefined,
@@ -27,12 +28,23 @@
       );
       // We now call .complete() again, to force an exception
       // because [[complete]] is true.
-      await promise_rejects(t, "InvalidStateError", response.complete(result));
+      const afterComplete = response.complete(result);
+      await promise_rejects(t, "InvalidStateError", afterComplete);
       button.innerHTML = `✅  ${button.textContent}`;
     } catch (err) {
       button.innerHTML = `❌  ${button.textContent}`;
       assert_unreached("Unexpected exception: " + err.message);
     }
+    const allPromises = new Set([
+      completePromise,
+      invalidComplete,
+      afterComplete,
+    ]);
+    assert_equals(
+      allPromises.length,
+      3,
+      "Calling complete() multiple times is always a new object."
+    );
   }, button.textContent.trim());
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.any.js b/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.any.js
rename to third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
index fdd9820..0ea7a2a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
@@ -650,7 +650,7 @@
 
         /**
          * Returns a Promise that will resolve after the specified event or
-         * series of events has occured.
+         * series of events has occurred.
          *
          * @param options An optional options object. If the 'record' property
          *                on this object has the value 'all', when the Promise
@@ -1059,7 +1059,7 @@
     function assert_array_approx_equals(actual, expected, epsilon, description)
     {
         /*
-         * Test if two primitive arrays are equal withing +/- epsilon
+         * Test if two primitive arrays are equal within +/- epsilon
          */
         assert(actual.length === expected.length,
                "assert_array_approx_equals", description,
@@ -1087,7 +1087,7 @@
     function assert_approx_equals(actual, expected, epsilon, description)
     {
         /*
-         * Test if two primitive numbers are equal withing +/- epsilon
+         * Test if two primitive numbers are equal within +/- epsilon
          */
         assert(typeof actual === "number",
                "assert_approx_equals", description,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
index 79d93e8..16b331f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
@@ -3,6 +3,7 @@
 PASS test setup (cache creation)
 FAIL Event constructors assert_equals: FetchEvent.isReload should not exist expected (undefined) undefined but got (boolean) false
 PASS xhr is not exposed
+PASS URL.createObjectURL is not exposed
 FAIL ServiceWorker interface: existence and properties of interface object assert_own_property: self does not have own property "ServiceWorker" expected property "ServiceWorker" missing
 FAIL ServiceWorker interface object length assert_own_property: self does not have own property "ServiceWorker" expected property "ServiceWorker" missing
 FAIL ServiceWorker interface object name assert_own_property: self does not have own property "ServiceWorker" expected property "ServiceWorker" missing
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
index 10fe14d5..56bc8af4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
@@ -93,3 +93,7 @@
 test(() => {
     assert_false('XMLHttpRequest' in self);
   }, 'xhr is not exposed');
+
+test(() => {
+    assert_false('createObjectURL' in self.URL);
+  }, 'URL.createObjectURL is not exposed')
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001-ref.svg
new file mode 100644
index 0000000..871003f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001-ref.svg
@@ -0,0 +1,48 @@
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Marker: 'orient'</title>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("../fonts/FreeSans.woff") format("woff");
+    }
+    text {
+      font-family: FreeSans, sans-serif;
+      text-anchor: middle;
+      fill: black;
+    }
+    #title {
+      font-size: 24px;
+    }
+    .label {
+      font-size: 18px;
+    }
+  </style>
+
+  <defs>
+    <path id="triangle" d="m 0,0 0,-2.5 10,2.5 -10,2.5 z"/>
+  </defs>
+
+  <g id="test-body-reference" style="fill:black">
+    <path d="m 120,120 120,0 120,0" style="stroke:black;stroke-width:4px"/>
+    <path d="m 120,220 120,0 120,0" style="stroke:black;stroke-width:4px"/>
+    <path d="m 120,320 120,0 120,0" style="stroke:black;stroke-width:4px"/>
+    <use xlink:href="#triangle" transform="translate(120,120) scale(4,4)"/>
+    <use xlink:href="#triangle" transform="translate(240,120) scale(4,4)"/>
+    <use xlink:href="#triangle" transform="translate(360,120) scale(4,4)"/>
+    <use xlink:href="#triangle" transform="translate(120,220) scale(4,4) rotate(45)"/>
+    <use xlink:href="#triangle" transform="translate(240,220) scale(4,4) rotate(45)"/>
+    <use xlink:href="#triangle" transform="translate(360,220) scale(4,4) rotate(45)"/>
+    <use xlink:href="#triangle" transform="translate(120,320) scale(4,4) rotate(180)"/>
+    <use xlink:href="#triangle" transform="translate(240,320) scale(4,4)"/>
+    <use xlink:href="#triangle" transform="translate(360,320) scale(4,4)"/>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001.svg
new file mode 100644
index 0000000..55c2394
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/reftests/markers-orient-001.svg
@@ -0,0 +1,65 @@
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Marker: 'orient'</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="http://tavmjong.free.fr"/>
+    <html:link rel="help"
+          href="https://www.w3.org/TR/SVG2/painting.html#OrientAttribute"/>
+    <html:link rel="match"  href="markers-orient-001-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("../fonts/FreeSans.woff") format("woff");
+    }
+    text {
+      font-family: FreeSans, sans-serif;
+      text-anchor: middle;
+      fill: black;
+    }
+    #title {
+      font-size: 24px;
+    }
+    .label {
+      font-size: 18px;
+    }
+  </style>
+
+  <defs>
+    <path id="triangle" d="m 0,0 0,-2.5 10,2.5 -10,2.5 z"/>
+    <marker id="OrientAuto" style="overflow:visible" markerWidth="5" markerHeight="10">
+      <use xlink:href="#triangle"/>
+    </marker>
+    <marker id="OrientFixed" style="overflow:visible" markerWidth="5" markerHeight="10" orient="45">
+      <use xlink:href="#triangle"/>
+    </marker>
+    <marker id="OrientAutoReverse" style="overflow:visible" markerWidth="5" markerHeight="10" orient="auto-start-reverse">
+      <use xlink:href="#triangle"/>
+    </marker>
+  </defs>
+
+  <g id="reference" style="fill:red">
+      <use xlink:href="#triangle" transform="translate(120,120) scale(4,4)"/>
+      <use xlink:href="#triangle" transform="translate(240,120) scale(4,4)"/>
+      <use xlink:href="#triangle" transform="translate(360,120) scale(4,4)"/>
+      <use xlink:href="#triangle" transform="translate(120,220) scale(4,4) rotate(45)"/>
+      <use xlink:href="#triangle" transform="translate(240,220) scale(4,4) rotate(45)"/>
+      <use xlink:href="#triangle" transform="translate(360,220) scale(4,4) rotate(45)"/>
+      <use xlink:href="#triangle" transform="translate(120,320) scale(4,4) rotate(180)"/>
+      <use xlink:href="#triangle" transform="translate(240,320) scale(4,4)"/>
+      <use xlink:href="#triangle" transform="translate(360,320) scale(4,4)"/>
+  </g>
+  <g id="test-body-content" font-size="16">
+    <path d="m 120,120 120,0 120,0" style="stroke:black;stroke-width:4px;marker:url(#OrientAuto)"/>
+    <path d="m 120,220 120,0 120,0" style="stroke:black;stroke-width:4px;marker:url(#OrientFixed)"/>
+    <path d="m 120,320 120,0 120,0" style="stroke:black;stroke-width:4px;marker:url(#OrientAutoReverse)"/>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001-ref.svg
new file mode 100644
index 0000000..6abd21158
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 001</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px;fill:black">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="240" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="400" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="400" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001.svg
new file mode 100644
index 0000000..ae1a10d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-001.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 001</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-001-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="inline-size:320px;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="400" y="114.8" style="inline-size:320px;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002-ref.svg
new file mode 100644
index 0000000..66f771e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 002</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text transform="translate(250,10) rotate(90)">
+        <tspan x="90" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="90" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(80,0)">
+      <text transform="translate(250,-40) rotate(90)" style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="240" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(160,0)">
+      <text transform="translate(250,-90) rotate(90)" style="text-anchor:end">
+        <tspan x="390" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="390" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002.svg
new file mode 100644
index 0000000..141909c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-002.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 002</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-002-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;writing-mode:tb-rl">
+    <g transform="translate(0,0)">
+      <text x="140" y="100" style="inline-size:200px">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(80,0)">
+      <text x="140" y="200" style="inline-size:200px;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(160,0)">
+      <text x="140" y="300" style="inline-size:200px;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003-ref.svg
new file mode 100644
index 0000000..289b92a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 003</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px;direction:rtl">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="400" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="400" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="240" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="80" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="80" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003.svg
new file mode 100644
index 0000000..9fcab5b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-003.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 003</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-003-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;direction:rtl">
+    <g transform="translate(0,0)">
+      <text x="400" y="114.8" style="inline-size:320px">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="inline-size:320px;text-anchor:middle">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="80" y="114.8" style="inline-size:320px;text-anchor:end">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005-ref.svg
new file mode 100644
index 0000000..af756b6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005-ref.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 005</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="149.6">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="174.8">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="209.6">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="234.8">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="254.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005.svg
new file mode 100644
index 0000000..e6a1d75
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-005.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 005</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-005-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-height:1.25">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px" xml:space="preserve">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006-ref.svg
new file mode 100644
index 0000000..9c32e841
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006-ref.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="154.8">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="174.8">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="194.8">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="214.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006.svg
new file mode 100644
index 0000000..b84e3d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-006.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-006-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-height:1.25">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px;line-height:0">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em;line-height:0">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007-ref.svg
new file mode 100644
index 0000000..1817851
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007-ref.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="139.6">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="159.6">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="184.4">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="204.4">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="226.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007.svg
new file mode 100644
index 0000000..9d18b52
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-007.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-007-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px;line-height:20px">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101-ref.svg
new file mode 100644
index 0000000..ab41dea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 101</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="240" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="400" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="400" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101.svg
new file mode 100644
index 0000000..fa8bf5ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-101.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 101</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-101-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:66.66667%">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="inline-size:66.66667%;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="400" y="114.8" style="inline-size:66.66667%;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201-ref.svg
new file mode 100644
index 0000000..b1eb7c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201-ref.svg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 201</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text style="writing-mode:tb-rl">
+        <tspan x="140" y="100">漢字</tspan>
+        <tspan x="140" y="132">Lorem ipsum</tspan>
+        <tspan x="140" y="227.7">漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(80,0)">
+      <text transform="translate(250,-40) rotate(90)">
+        <tspan x="140" y="110">漢字Lorem ipsum!漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(160,0)">
+      <text transform="translate(250,-40) rotate(90)">
+        <tspan x="140" y="110">漢字!لكن لا بد أن漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(240,0)">
+      <text transform="translate(250,-40) rotate(90)" style="direction:rtl;text-anchor:end">
+        <tspan x="140" y="110">漢字!لكن لا بد أن漢字</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201.svg
new file mode 100644
index 0000000..5ab3213
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-inline-size-201.svg
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 201</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <html:link rel="match"  href="text-inline-size-201-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <!-- Lorem ipsum dolor sit amet, consectetur adipisicing elit, -->
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;writing-mode:tb-rl">
+    <g transform="translate(0,0)">
+      <text x="140" y="100" style="inline-size:200px">漢字Lorem ipsum!漢字</text>
+    </g>
+    <g transform="translate(80,0)" style="text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字Lorem ipsum!漢字</text>
+    </g>
+    <g transform="translate(160,0)" style="text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字!لكن لا بد أن漢字</text>
+    </g>
+    <g transform="translate(240,0)" style="direction:rtl;text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字!لكن لا بد أن漢字</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001-ref.svg
new file mode 100644
index 0000000..9238a88
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 001</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px;fill:black">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="240" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="400" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="400" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001.svg
new file mode 100644
index 0000000..1272f56b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-001.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 001</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#TextLayoutPreMultiline"/>
+    <html:link rel="match"  href="text-multiline-001-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="white-space: pre-line">Lorem ipsum dolor sit amet, consectetur
+adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="white-space: pre-line;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur
+adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="400" y="114.8" style="white-space: pre-line;text-anchor:end">Lorem ipsum dolor sit amet, consectetur
+      adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002-ref.svg
new file mode 100644
index 0000000..5ba04b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 002</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px">
+    <g transform="translate(0,0)">
+      <text transform="translate(250,10) rotate(90)">
+        <tspan x="90" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="90" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(80,0)">
+      <text transform="translate(250,-40) rotate(90)" style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="240" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(160,0)">
+      <text transform="translate(250,-90) rotate(90)" style="text-anchor:end">
+        <tspan x="390" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="390" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002.svg
new file mode 100644
index 0000000..e109351
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-002.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 002</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#TextLayoutPreMultiline"/>
+    <html:link rel="match"  href="text-multiline-002-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;writing-mode:tb-rl">
+    <g transform="translate(0,0)">
+      <text x="140" y="100" style="white-space: pre-line">Lorem ipsum dolor sit amet,
+consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(80,0)">
+      <text x="140" y="200" style="white-space: pre-line;text-anchor:middle">Lorem ipsum dolor sit amet,
+consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(160,0)">
+      <text x="140" y="300" style="white-space: pre-line;text-anchor:end">Lorem ipsum dolor sit amet,
+consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003-ref.svg
new file mode 100644
index 0000000..cbfce51b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003-ref.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 003</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-reference" style="font-size:16px;direction:rtl">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="400" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="400" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="240" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="80" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="80" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003.svg
new file mode 100644
index 0000000..e52bb7705
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/reftests/text-multiline-003.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Multiline — 003</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#TextLayoutPreMultiline"/>
+    <html:link rel="match"  href="text-multiline-003-ref.svg" />
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;direction:rtl">
+    <g transform="translate(0,0)">
+      <text x="400" y="114.8" style="white-space: pre-line">لكن لا بد أن أوضح لك أن كل هذه الأفكار
+المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="white-space: pre-line;text-anchor:middle">لكن لا بد أن أوضح لك أن كل هذه الأفكار
+المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="80" y="114.8" style="white-space: pre-line;text-anchor:end">لكن لا بد أن أوضح لك أن كل هذه الأفكار
+المغلوطة حول استنكار</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-001-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-001-visual.svg
new file mode 100644
index 0000000..086bab3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-001-visual.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 001</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,40 m 320,-40 0,40"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 001</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <circle cx="80" cy="114.8" r="1,0" style="fill:lightblue"/>
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <circle cx="240" cy="114.8" r="1,0" style="fill:lightblue"/>
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="240" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <circle cx="400" cy="114.8" r="1,0" style="fill:lightblue"/>
+      <text style="text-anchor:end">
+        <tspan x="400" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="400" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;fill:green">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="inline-size:320px;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="400" y="114.8" style="inline-size:320px;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-002-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-002-visual.svg
new file mode 100644
index 0000000..7f58973c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-002-visual.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 002</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 110,100 40,0 m -40,200 40,0"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 002</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <text transform="translate(250,10) rotate(90)">
+        <tspan x="90" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="90" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(80,0)">
+      <text transform="translate(250,-40) rotate(90)" style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="240" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(160,0)">
+      <text transform="translate(250,-90) rotate(90)" style="text-anchor:end">
+        <tspan x="390" y="114.8">Lorem ipsum dolor sit amet,</tspan>
+        <tspan x="390" y="134.8">consectetur adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;writing-mode:tb-rl;fill:green">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="140" y="100" style="inline-size:200px">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(80,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="140" y="200" style="inline-size:200px;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(160,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="140" y="300" style="inline-size:200px;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-003-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-003-visual.svg
new file mode 100644
index 0000000..19bf0dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-003-visual.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 003</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,40 m 320,-40 0,40"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 003</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;direction:rtl;fill:red">
+    <g transform="translate(0,0)">
+      <text>
+        <tspan x="400" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="400" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="240" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <text style="text-anchor:end">
+        <tspan x="80" y="114.8">لكن لا بد أن أوضح لك أن كل هذه الأفكار</tspan>
+        <tspan x="80" y="134.8">المغلوطة حول استنكار</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;direction:rtl;fill:green">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="400" y="114.8" style="inline-size:320px">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,60)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="240" y="114.8" style="inline-size:320px;text-anchor:middle">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+    <g transform="translate(0,120)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text x="80" y="114.8" style="inline-size:320px;text-anchor:end">لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-005-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-005-visual.svg
new file mode 100644
index 0000000..dab467e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-005-visual.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 005</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,160 m 320,-160 0,160"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 005</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:#ffeeee">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="149.6">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="174.8">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="209.6">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="234.8">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="254.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-height:1.25;fill:green">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px" xml:space="preserve">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-006-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-006-visual.svg
new file mode 100644
index 0000000..427ff09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-006-visual.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,160 m 320,-160 0,160"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 006</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="154.8">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="174.8">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="194.8">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="214.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-height:1.25;fill:green">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px;line-height:0">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em;line-height:0">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-007-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-007-visual.svg
new file mode 100644
index 0000000..8bb078f9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-007-visual.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 006</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,160 m 320,-160 0,160"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 007</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="139.6">adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor</tspan>
+        <tspan x="80" y="159.6">incididunt ut labore et dolore magna aliqua. Ut</tspan>
+        <tspan x="80" y="184.4">enim ad minim veniam, <tspan style="font-size:32px">quis</tspan> nostrud</tspan>
+        <tspan x="80" y="204.4">exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea</tspan>
+        <tspan x="80" y="226.8">commodo consequat.</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;fill:green">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:320px;line-height:20px">Lorem ipsum dolor sit amet, consectetur adipiscing <tspan style="font-size:32px">elit</tspan>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, <tspan style="font-size:2em">quis</tspan> nostrud exercitation ullamco laboris <tspan style="font-size:8px">nisi</tspan> ut aliquip ex ea commodo consequat.</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-101-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-101-visual.svg
new file mode 100644
index 0000000..e1c5c416
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-101-visual.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text: Inline Size — 101</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 80,100 0,40 m 320,-40 0,40"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 101</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text>
+        <tspan x="80" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="80" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,60)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text style="text-anchor:middle">
+        <tspan x="240" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="240" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+    <g transform="translate(0,120)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text style="text-anchor:end">
+        <tspan x="400" y="114.8">Lorem ipsum dolor sit amet, consectetur</tspan>
+        <tspan x="400" y="134.8">adipisicing elit,</tspan>
+      </text>
+    </g>
+  </g>
+
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;fill:green">
+    <g transform="translate(0,0)">
+      <text x="80" y="114.8" style="inline-size:66.66667%">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,60)">
+      <text x="240" y="114.8" style="inline-size:66.66667%;text-anchor:middle">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+    <g transform="translate(0,120)">
+      <text x="400" y="114.8" style="inline-size:66.66667%;text-anchor:end">Lorem ipsum dolor sit amet, consectetur adipisicing elit,</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-201-visual.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-201-visual.svg
new file mode 100644
index 0000000..f2649ea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/text/visualtests/text-inline-size-201-visual.svg
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink"
+  xmlns:html="http://www.w3.org/1999/xhtml">
+  <g id="testmeta">
+    <title>Text in Shape — 201</title>
+    <html:link rel="author"
+          title="Tavmjong Bah"
+          href="mailto:tavmjong@free.fr"/>
+    <html:link rel="reviewer"
+          title="NAME_OF_REVIEWER"
+          href="mailto:EMAIL OR http://CONTACT_PAGE" />
+          <!-- YYYY-MM-DD -->
+    <html:link rel="help"
+          href="https://svgwg.org/svg2-draft/text.html#InlineSize"/>
+    <metadata class="flags">TOKENS</metadata>
+    <desc class="assert">TEST ASSERTION</desc>
+  </g>
+
+  <style id="test-font" type="text/css">
+    /* Standard Font (if needed). */
+    @font-face {
+      font-family: FreeSans;
+      src: url("fonts/FreeSans.woff") format("woff"),
+           local("FreeSans");
+    }
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <style id="test-style" type="text/css">
+    /* Style that is being tested (if needed). */
+    text { font-family: FreeSans, sans-serif }
+  </style>
+
+  <defs>
+    <path id="TestPath" d="m 110,100 40,0 m -40,200 40,0"/>
+  </defs>
+
+  <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Text 'inline-size' — 201</text>
+  <a href="https://svgwg.org/svg2-draft/text.html#InlineSize">
+    <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/text.html#InlineSize</text>
+  </a>
+
+  <g id="test-body-reference" style="font-size:16px;fill:red">
+    <g transform="translate(0,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text style="writing-mode:tb-rl">
+        <tspan x="140" y="100">漢字</tspan>
+        <tspan x="140" y="132">Lorem ipsum</tspan>
+        <tspan x="140" y="227.7">漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(80,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text transform="translate(250,-40) rotate(90)">
+        <tspan x="140" y="110">漢字Lorem ipsum!漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(160,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text transform="translate(250,-40) rotate(90)">
+        <tspan x="140" y="110">漢字!لكن لا بد أن漢字</tspan>
+      </text>
+    </g>
+    <g transform="translate(240,0)">
+      <use xlink:href="#TestPath" style="fill:none;stroke:lightblue"/>
+      <text transform="translate(250,-40) rotate(90)" style="direction:rtl;text-anchor:end">
+        <tspan x="140" y="110">漢字!لكن لا بد أن漢字</tspan>
+      </text>
+    </g>
+  </g>
+
+  <!-- Lorem ipsum dolor sit amet, consectetur adipisicing elit, -->
+  <g id="test-body-content" style="font-size:16px;line-spacing:1.25;writing-mode:tb-rl;fill:green">
+    <g transform="translate(0,0)">
+      <text x="140" y="100" style="inline-size:200px">漢字Lorem ipsum!漢字</text>
+    </g>
+    <g transform="translate(80,0)" style="text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字Lorem ipsum!漢字</text>
+    </g>
+    <g transform="translate(160,0)" style="text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字!لكن لا بد أن漢字</text>
+    </g>
+    <g transform="translate(240,0)" style="direction:rtl;text-orientation:sideways">
+      <text x="140" y="100" style="inline-size:200px">漢字!لكن لا بد أن漢字</text>
+    </g>
+  </g>
+
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events-expected.txt
new file mode 100644
index 0000000..e60970b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL oncut: DocumentAndElementEventHandlers must be on SVGElement not Element assert_true: SVGElement has an own property named "oncut" expected true got false
+PASS oncut: the default value must be null
+PASS oncut: the content attribute must be compiled into a function as the corresponding property
+PASS oncut: the content attribute must execute when an event is dispatched
+FAIL oncopy: DocumentAndElementEventHandlers must be on SVGElement not Element assert_true: SVGElement has an own property named "oncopy" expected true got false
+PASS oncopy: the default value must be null
+PASS oncopy: the content attribute must be compiled into a function as the corresponding property
+PASS oncopy: the content attribute must execute when an event is dispatched
+FAIL onpaste: DocumentAndElementEventHandlers must be on SVGElement not Element assert_true: SVGElement has an own property named "onpaste" expected true got false
+PASS onpaste: the default value must be null
+PASS onpaste: the content attribute must be compiled into a function as the corresponding property
+PASS onpaste: the content attribute must execute when an event is dispatched
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events.svg
new file mode 100644
index 0000000..fa813dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/event-handler-all-document-element-events.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:h="http://www.w3.org/1999/xhtml">
+    <title>DocumentAndElementEventHandlers</title>
+    <metadata>
+        <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#InterfaceSVGElement"/>
+    </metadata>
+    <h:script src="/resources/testharness.js"/>
+    <h:script src="/resources/testharnessreport.js"/>
+    <script><![CDATA[
+        "use strict";
+        setup({ explicit_done: true });
+
+        const names = ["oncut","oncopy","onpaste"];
+
+        for (const name of names) {
+            const withoutOn = name.substring(2);
+
+            test(() => {
+                assert_true(SVGElement.prototype.hasOwnProperty(name),
+                    `${SVGElement.prototype.constructor.name} has an own property named "${name}"`);
+                assert_false(name in Element.prototype, `Element.prototype must not contain a "${name}" property`);
+            }, `${name}: DocumentAndElementEventHandlers must be on SVGElement not Element`);
+
+            test(() => {
+                const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
+
+                assert_equals(svgElement[name], null,
+                    `The default value of the property is null for a ${svgElement.constructor.name} instance`);
+            }, `${name}: the default value must be null`);
+
+            test(() => {
+                const el = document.createElementNS("http://www.w3.org/2000/svg", "g");
+                el.setAttribute(name, `window.${name}Happened = true;`);
+                const compiledHandler = el[name];
+
+                assert_equals(typeof compiledHandler, "function", `The ${name} property must be a function`);
+                compiledHandler();
+                assert_true(window[name + "Happened"], "Calling the handler must run the code");
+            }, `${name}: the content attribute must be compiled into a function as the corresponding property`);
+
+            test(() => {
+                const el = document.createElementNS("http://www.w3.org/2000/svg", "g");
+                el.setAttribute(name, `window.${name}Happened2 = true;`);
+
+                el.dispatchEvent(new Event(withoutOn));
+
+                assert_true(window[name + "Happened2"], "Dispatching an event must run the code");
+            }, `${name}: the content attribute must execute when an event is dispatched`);
+        }
+
+        done();
+  ]]></script>
+</svg>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/assertions.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/assertions.js
new file mode 100644
index 0000000..151a406
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/assertions.js
@@ -0,0 +1,17 @@
+function assert_function_name(fn, name, description) {
+  const propdesc = Object.getOwnPropertyDescriptor(fn, "name");
+  assert_equals(typeof propdesc, "object", `${description} should have name property`);
+  assert_false(propdesc.writable, "writable", `${description} name should not be writable`);
+  assert_false(propdesc.enumerable, "enumerable", `${description} name should not be enumerable`);
+  assert_true(propdesc.configurable, "configurable", `${description} name should be configurable`);
+  assert_equals(propdesc.value, name, `${description} name should be ${name}`);
+}
+
+function assert_function_length(fn, length, description) {
+  const propdesc = Object.getOwnPropertyDescriptor(fn, "length");
+  assert_equals(typeof propdesc, "object", `${description} should have length property`);
+  assert_false(propdesc.writable, "writable", `${description} length should not be writable`);
+  assert_false(propdesc.enumerable, "enumerable", `${description} length should not be enumerable`);
+  assert_true(propdesc.configurable, "configurable", `${description} length should be configurable`);
+  assert_equals(propdesc.value, length, `${description} length should be ${length}`);
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/bad-imports.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/bad-imports.js
new file mode 100644
index 0000000..f076baa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/bad-imports.js
@@ -0,0 +1,140 @@
+function test_bad_imports(t) {
+  for (const value of [null, true, "", Symbol(), 1, 0.1, NaN]) {
+    t(`Non-object imports argument: ${format_value(value)}`,
+      new TypeError(),
+      builder => {},
+      value);
+  }
+
+  for (const value of [undefined, null, true, "", Symbol(), 1, 0.1, NaN]) {
+    const imports = {
+      "module": value,
+    };
+    t(`Non-object module: ${format_value(value)}`,
+      new TypeError(),
+      builder => {
+        builder.addImport("module", "fn", kSig_v_v);
+      },
+      value);
+  }
+
+  t(`Missing imports argument`,
+    new TypeError(),
+    builder => {
+      builder.addImport("module", "fn", kSig_v_v);
+    });
+
+  for (const [value, name] of [[undefined, "undefined"], [{}, "empty object"], [{ "module\0": null }, "wrong property"]]) {
+    t(`Imports argument with missing property: ${name}`,
+      new TypeError(),
+      builder => {
+        builder.addImport("module", "fn", kSig_v_v);
+      },
+      value);
+  }
+
+  t(`Importing an i64 global`,
+    new WebAssembly.LinkError(),
+    builder => {
+      builder.addImportedGlobal("module", "global", kWasmI64);
+    },
+    {
+      "module": {
+        "global": 0,
+      },
+    });
+
+  for (const value of [undefined, null, true, "", Symbol(), 1, 0.1, NaN, {}]) {
+    t(`Importing a function with an incorrectly-typed value: ${format_value(value)}`,
+      new WebAssembly.LinkError(),
+      builder => {
+        builder.addImport("module", "fn", kSig_v_v);
+      },
+      {
+        "module": {
+          "fn": value,
+        },
+      });
+  }
+
+  const nonGlobals = [
+    [undefined],
+    [null],
+    [true],
+    [""],
+    [Symbol()],
+    [{}, "plain object"],
+    [WebAssembly.Global, "WebAssembly.Global"],
+    [WebAssembly.Global.prototype, "WebAssembly.Global.prototype"],
+    [Object.create(WebAssembly.Global.prototype), "Object.create(WebAssembly.Global.prototype)"],
+  ];
+
+  for (const [value, name = format_value(value)] of nonGlobals) {
+    t(`Importing a global with an incorrectly-typed value: ${name}`,
+      new WebAssembly.LinkError(),
+      builder => {
+        builder.addImportedGlobal("module", "global", kWasmI32);
+      },
+      {
+        "module": {
+          "global": value,
+        },
+      });
+  }
+
+  const nonMemories = [
+    [undefined],
+    [null],
+    [true],
+    [""],
+    [Symbol()],
+    [1],
+    [0.1],
+    [NaN],
+    [{}, "plain object"],
+    [WebAssembly.Memory, "WebAssembly.Memory"],
+    [WebAssembly.Memory.prototype, "WebAssembly.Memory.prototype"],
+    [Object.create(WebAssembly.Memory.prototype), "Object.create(WebAssembly.Memory.prototype)"],
+  ];
+
+  for (const [value, name = format_value(value)] of nonMemories) {
+    t(`Importing memory with an incorrectly-typed value: ${name}`,
+      new WebAssembly.LinkError(),
+      builder => {
+        builder.addImportedMemory("module", "memory", 0, 128);
+      },
+      {
+        "module": {
+          "memory": value,
+        },
+      });
+  }
+
+  const nonTables = [
+    [undefined],
+    [null],
+    [true],
+    [""],
+    [Symbol()],
+    [1],
+    [0.1],
+    [NaN],
+    [{}, "plain object"],
+    [WebAssembly.Table, "WebAssembly.Table"],
+    [WebAssembly.Table.prototype, "WebAssembly.Table.prototype"],
+    [Object.create(WebAssembly.Table.prototype), "Object.create(WebAssembly.Table.prototype)"],
+  ];
+
+  for (const [value, name = format_value(value)] of nonTables) {
+    t(`Importing table with an incorrectly-typed value: ${name}`,
+      new WebAssembly.LinkError(),
+      builder => {
+        builder.addImportedTable("module", "table", 0, 128);
+      },
+      {
+        "module": {
+          "table": value,
+        },
+      });
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js
new file mode 100644
index 0000000..8670029
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js
@@ -0,0 +1,23 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/bad-imports.js
+
+test_bad_imports((name, error, build, ...arguments) => {
+  promise_test(t => {
+    const builder = new WasmModuleBuilder();
+    build(builder);
+    const buffer = builder.toBuffer();
+    const module = new WebAssembly.Module(buffer);
+    return promise_rejects(t, error, WebAssembly.instantiate(module, ...arguments));
+  }, `WebAssembly.instantiate(module): ${name}`);
+});
+
+test_bad_imports((name, error, build, ...arguments) => {
+  promise_test(t => {
+    const builder = new WasmModuleBuilder();
+    build(builder);
+    const buffer = builder.toBuffer();
+    return promise_rejects(t, error, WebAssembly.instantiate(buffer, ...arguments));
+  }, `WebAssembly.instantiate(buffer): ${name}`);
+});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js
new file mode 100644
index 0000000..24c51c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js
@@ -0,0 +1,14 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/bad-imports.js
+
+test_bad_imports((name, error, build, ...arguments) => {
+  test(() => {
+    const builder = new WasmModuleBuilder();
+    build(builder);
+    const buffer = builder.toBuffer();
+    const module = new WebAssembly.Module(buffer);
+    assert_throws(error, () => new WebAssembly.Instance(module, ...arguments));
+  }, `new WebAssembly.Instance(module): ${name}`);
+});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor.any.js
new file mode 100644
index 0000000..93a3ffda
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/instance/constructor.any.js
@@ -0,0 +1,193 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/assertions.js
+
+function assert_exported_function(fn, { name, length }, description) {
+  assert_equals(Object.getPrototypeOf(fn), Function.prototype,
+                `${description}: prototype`);
+
+  assert_function_name(fn, name, description);
+  assert_function_length(fn, length, description);
+}
+
+function assert_Instance(instance, expected_exports) {
+  assert_equals(Object.getPrototypeOf(instance), WebAssembly.Instance.prototype,
+                "prototype");
+  assert_true(Object.isExtensible(instance), "extensible");
+
+  assert_equals(instance.exports, instance.exports, "exports should be idempotent");
+  const exports = instance.exports;
+
+  assert_equals(Object.getPrototypeOf(exports), null, "exports prototype");
+  assert_false(Object.isExtensible(exports), "extensible exports");
+  for (const [key, expected] of Object.entries(expected_exports)) {
+    const property = Object.getOwnPropertyDescriptor(exports, key);
+    assert_equals(typeof property, "object", `${key} should be present`);
+    assert_false(property.writable, `${key}: writable`);
+    assert_true(property.enumerable, `${key}: enumerable`);
+    assert_false(property.configurable, `${key}: configurable`);
+    const actual = property.value;
+
+    switch (expected.kind) {
+    case "function":
+      assert_exported_function(actual, expected, `value of ${key}`);
+      break;
+    case "global":
+      assert_equals(Object.getPrototypeOf(actual), WebAssembly.Global.prototype,
+                    `value of ${key}: prototype`);
+      assert_equals(actual.value, expected.value, `value of ${key}: value`);
+      assert_equals(actual.valueOf(), expected.value, `value of ${key}: valueOf()`);
+      break;
+    case "memory":
+      assert_equals(Object.getPrototypeOf(actual), WebAssembly.Memory.prototype,
+                    `value of ${key}: prototype`);
+      assert_equals(Object.getPrototypeOf(actual.buffer), ArrayBuffer.prototype,
+                    `value of ${key}: prototype of buffer`);
+      assert_equals(actual.buffer.byteLength, 0x10000 * expected.size, `value of ${key}: size of buffer`);
+      const array = new Uint8Array(actual.buffer);
+      assert_equals(array[0], 0, `value of ${key}: first element of buffer`);
+      assert_equals(array[array.byteLength - 1], 0, `value of ${key}: last element of buffer`);
+      break;
+    case "table":
+      assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype,
+                    `value of ${key}: prototype`);
+      assert_equals(actual.length, expected.length, `value of ${key}: length of table`);
+      break;
+    }
+  }
+}
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_function_name(WebAssembly.Instance, "Instance", "WebAssembly.Instance");
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Instance, 1, "WebAssembly.Instance");
+}, "length");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Instance());
+}, "No arguments");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_throws(new TypeError(), () => WebAssembly.Instance(module));
+}, "Calling");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const arguments = [
+    [],
+    [undefined],
+    [{}],
+  ];
+  for (const value of arguments) {
+    const instance = new WebAssembly.Instance(module, ...arguments);
+    assert_Instance(instance, {});
+  }
+}, "Empty module");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+  builder.addImportedGlobal("module", "global1", kWasmI32);
+  builder.addImportedGlobal("module", "global2", kWasmI32);
+  const buffer = builder.toBuffer();
+  const module = new WebAssembly.Module(buffer);
+  const order = [];
+  const imports = {
+    get module() {
+      order.push("module getter");
+      return {
+        get global1() {
+          order.push("global1 getter");
+          return 0;
+        },
+        get global2() {
+          order.push("global2 getter");
+          return 0;
+        },
+      }
+    },
+  };
+  new WebAssembly.Instance(module, imports);
+  const expected = [
+    "module getter",
+    "global1 getter",
+    "module getter",
+    "global2 getter",
+  ];
+  assert_array_equals(order, expected);
+}, "getter order for imports object");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addImport("module", "fn", kSig_v_v);
+  builder.addImportedGlobal("module", "global", kWasmI32);
+  builder.addImportedMemory("module", "memory", 0, 128);
+  builder.addImportedTable("module", "table", 0, 128);
+
+  const buffer = builder.toBuffer();
+  const module = new WebAssembly.Module(buffer);
+  const instance = new WebAssembly.Instance(module, {
+    "module": {
+      "fn": function() {},
+      "global": 0,
+      "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }),
+      "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }),
+    },
+    get "module2"() {
+      assert_unreached("Should not get modules that are not imported");
+    },
+  });
+  assert_Instance(instance, {});
+}, "imports");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder
+    .addFunction("fn", kSig_v_d)
+    .addBody([
+        kExprEnd
+    ])
+    .exportFunc();
+  builder
+    .addFunction("fn2", kSig_v_v)
+    .addBody([
+        kExprEnd
+    ])
+    .exportFunc();
+
+  builder.setFunctionTableLength(1);
+  builder.addExportOfKind("table", kExternalTable, 0);
+
+  builder.addGlobal(kWasmI32, true)
+    .exportAs("global")
+    .init = 7;
+  builder.addGlobal(kWasmF64, true)
+    .exportAs("global2")
+    .init = 1.2;
+
+  builder.addMemory(4, 8, true);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+
+  const instance = new WebAssembly.Instance(module, {});
+  const expected = {
+    "fn": { "kind": "function", "name": "0", "length": 1 },
+    "fn2": { "kind": "function", "name": "1", "length": 0 },
+    "table": { "kind": "table", "length": 1 },
+    "global": { "kind": "global", "value": 7 },
+    "global2": { "kind": "global", "value": 1.2 },
+    "memory": { "kind": "memory", "size": 4 },
+  };
+  assert_Instance(instance, expected);
+}, "exports");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any-expected.txt
new file mode 100644
index 0000000..5fdc3310
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any-expected.txt
@@ -0,0 +1,67 @@
+This is a testharness.js-based test.
+Found 63 tests; 48 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS WebAssembly: property descriptor
+PASS WebAssembly: constructing
+PASS WebAssembly.Module: property descriptor
+PASS WebAssembly.Module: prototype
+PASS WebAssembly.Instance: property descriptor
+PASS WebAssembly.Instance: prototype
+PASS WebAssembly.Memory: property descriptor
+PASS WebAssembly.Memory: prototype
+PASS WebAssembly.Table: property descriptor
+PASS WebAssembly.Table: prototype
+PASS WebAssembly.Global: property descriptor
+PASS WebAssembly.Global: prototype
+PASS WebAssembly.CompileError: property descriptor
+PASS WebAssembly.CompileError: prototype
+PASS WebAssembly.LinkError: property descriptor
+PASS WebAssembly.LinkError: prototype
+PASS WebAssembly.RuntimeError: property descriptor
+PASS WebAssembly.RuntimeError: prototype
+FAIL WebAssembly.validate assert_true: enumerable expected true got false
+PASS WebAssembly.validate: name
+PASS WebAssembly.validate: length
+FAIL WebAssembly.compile assert_true: enumerable expected true got false
+PASS WebAssembly.compile: name
+PASS WebAssembly.compile: length
+FAIL WebAssembly.instantiate assert_true: enumerable expected true got false
+PASS WebAssembly.instantiate: name
+PASS WebAssembly.instantiate: length
+FAIL WebAssembly.Module.exports assert_true: enumerable expected true got false
+PASS WebAssembly.Module.exports: name
+PASS WebAssembly.Module.exports: length
+FAIL WebAssembly.Module.imports assert_true: enumerable expected true got false
+PASS WebAssembly.Module.imports: name
+PASS WebAssembly.Module.imports: length
+FAIL WebAssembly.Module.customSections assert_true: enumerable expected true got false
+PASS WebAssembly.Module.customSections: name
+PASS WebAssembly.Module.customSections: length
+FAIL WebAssembly.Instance.exports assert_true: enumerable expected true got false
+PASS WebAssembly.Instance.exports: getter
+PASS WebAssembly.Instance.exports: setter
+FAIL WebAssembly.Memory.grow assert_true: enumerable expected true got false
+PASS WebAssembly.Memory.grow: name
+PASS WebAssembly.Memory.grow: length
+FAIL WebAssembly.Memory.buffer assert_true: enumerable expected true got false
+PASS WebAssembly.Memory.buffer: getter
+PASS WebAssembly.Memory.buffer: setter
+FAIL WebAssembly.Table.grow assert_true: enumerable expected true got false
+PASS WebAssembly.Table.grow: name
+PASS WebAssembly.Table.grow: length
+FAIL WebAssembly.Table.get assert_true: enumerable expected true got false
+PASS WebAssembly.Table.get: name
+PASS WebAssembly.Table.get: length
+FAIL WebAssembly.Table.set assert_true: enumerable expected true got false
+PASS WebAssembly.Table.set: name
+PASS WebAssembly.Table.set: length
+FAIL WebAssembly.Table.length assert_true: enumerable expected true got false
+PASS WebAssembly.Table.length: getter
+PASS WebAssembly.Table.length: setter
+FAIL WebAssembly.Global.valueOf assert_true: enumerable expected true got false
+PASS WebAssembly.Global.valueOf: name
+PASS WebAssembly.Global.valueOf: length
+FAIL WebAssembly.Global.value assert_true: enumerable expected true got false
+PASS WebAssembly.Global.value: getter
+PASS WebAssembly.Global.value: setter
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.js
new file mode 100644
index 0000000..64c1f60d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.js
@@ -0,0 +1,147 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+function test_operations(object, object_name, operations) {
+  for (const [name, length] of operations) {
+    test(() => {
+      const propdesc = Object.getOwnPropertyDescriptor(object, name);
+      assert_equals(typeof propdesc, "object");
+      assert_true(propdesc.writable, "writable");
+      assert_true(propdesc.enumerable, "enumerable");
+      assert_true(propdesc.configurable, "configurable");
+      assert_equals(propdesc.value, WebAssembly[name]);
+    }, `${object_name}.${name}`);
+
+    test(() => {
+      assert_function_name(object[name], name, `${object_name}.${name}`);
+    }, `${object_name}.${name}: name`);
+
+    test(() => {
+      assert_function_length(object[name], length, `${object_name}.${name}`);
+    }, `${object_name}.${name}: length`);
+  }
+}
+
+function test_attributes(object, object_name, attributes) {
+  for (const [name, mutable] of attributes) {
+    test(() => {
+      const propdesc = Object.getOwnPropertyDescriptor(object, name);
+      assert_equals(typeof propdesc, "object");
+      assert_true(propdesc.enumerable, "enumerable");
+      assert_true(propdesc.configurable, "configurable");
+    }, `${object_name}.${name}`);
+
+    test(() => {
+      const propdesc = Object.getOwnPropertyDescriptor(object, name);
+      assert_equals(typeof propdesc, "object");
+      assert_equals(typeof propdesc.get, "function");
+      assert_function_name(propdesc.get, "get " + name, `getter for "${name}"`);
+      assert_function_length(propdesc.get, 0, `getter for "${name}"`);
+    }, `${object_name}.${name}: getter`);
+
+    test(() => {
+      const propdesc = Object.getOwnPropertyDescriptor(object, name);
+      assert_equals(typeof propdesc, "object");
+      if (mutable) {
+        assert_equals(typeof propdesc.set, "function");
+        assert_function_name(propdesc.set, "set " + name, `setter for "${name}"`);
+        assert_function_length(propdesc.set, 1, `setter for "${name}"`);
+      } else {
+        assert_equals(typeof propdesc.set, "undefined");
+      }
+    }, `${object_name}.${name}: setter`);
+  }
+}
+
+test(() => {
+  const propdesc = Object.getOwnPropertyDescriptor(this, "WebAssembly");
+  assert_equals(typeof propdesc, "object");
+  assert_true(propdesc.writable, "writable");
+  assert_false(propdesc.enumerable, "enumerable");
+  assert_true(propdesc.configurable, "configurable");
+  assert_equals(propdesc.value, this.WebAssembly);
+}, "WebAssembly: property descriptor");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly());
+}, "WebAssembly: constructing");
+
+const interfaces = [
+  "Module",
+  "Instance",
+  "Memory",
+  "Table",
+  "Global",
+  "CompileError",
+  "LinkError",
+  "RuntimeError",
+];
+
+for (const name of interfaces) {
+  test(() => {
+    const propdesc = Object.getOwnPropertyDescriptor(WebAssembly, name);
+    assert_equals(typeof propdesc, "object");
+    assert_true(propdesc.writable, "writable");
+    assert_false(propdesc.enumerable, "enumerable");
+    assert_true(propdesc.configurable, "configurable");
+    assert_equals(propdesc.value, WebAssembly[name]);
+  }, `WebAssembly.${name}: property descriptor`);
+
+  test(() => {
+    const interface_object = WebAssembly[name];
+    const interface_prototype_object = interface_object.prototype;
+    const propdesc = Object.getOwnPropertyDescriptor(interface_prototype_object, "constructor");
+    assert_equals(typeof propdesc, "object");
+    assert_true(propdesc.writable, "writable");
+    assert_false(propdesc.enumerable, "enumerable");
+    assert_true(propdesc.configurable, "configurable");
+    assert_equals(propdesc.value, interface_object);
+  }, `WebAssembly.${name}: prototype`);
+}
+
+test_operations(WebAssembly, "WebAssembly", [
+  ["validate", 1],
+  ["compile", 1],
+  ["instantiate", 1],
+]);
+
+
+test_operations(WebAssembly.Module, "WebAssembly.Module", [
+  ["exports", 1],
+  ["imports", 1],
+  ["customSections", 2],
+]);
+
+
+test_attributes(WebAssembly.Instance.prototype, "WebAssembly.Instance", [
+  ["exports", false],
+]);
+
+
+test_operations(WebAssembly.Memory.prototype, "WebAssembly.Memory", [
+  ["grow", 1],
+]);
+
+test_attributes(WebAssembly.Memory.prototype, "WebAssembly.Memory", [
+  ["buffer", false],
+]);
+
+
+test_operations(WebAssembly.Table.prototype, "WebAssembly.Table", [
+  ["grow", 1],
+  ["get", 1],
+  ["set", 2],
+]);
+
+test_attributes(WebAssembly.Table.prototype, "WebAssembly.Table", [
+  ["length", false],
+]);
+
+
+test_operations(WebAssembly.Global.prototype, "WebAssembly.Global", [
+  ["valueOf", 0],
+]);
+
+test_attributes(WebAssembly.Global.prototype, "WebAssembly.Global", [
+  ["value", true],
+]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.worker-expected.txt
new file mode 100644
index 0000000..5fdc3310
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/interface.any.worker-expected.txt
@@ -0,0 +1,67 @@
+This is a testharness.js-based test.
+Found 63 tests; 48 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS WebAssembly: property descriptor
+PASS WebAssembly: constructing
+PASS WebAssembly.Module: property descriptor
+PASS WebAssembly.Module: prototype
+PASS WebAssembly.Instance: property descriptor
+PASS WebAssembly.Instance: prototype
+PASS WebAssembly.Memory: property descriptor
+PASS WebAssembly.Memory: prototype
+PASS WebAssembly.Table: property descriptor
+PASS WebAssembly.Table: prototype
+PASS WebAssembly.Global: property descriptor
+PASS WebAssembly.Global: prototype
+PASS WebAssembly.CompileError: property descriptor
+PASS WebAssembly.CompileError: prototype
+PASS WebAssembly.LinkError: property descriptor
+PASS WebAssembly.LinkError: prototype
+PASS WebAssembly.RuntimeError: property descriptor
+PASS WebAssembly.RuntimeError: prototype
+FAIL WebAssembly.validate assert_true: enumerable expected true got false
+PASS WebAssembly.validate: name
+PASS WebAssembly.validate: length
+FAIL WebAssembly.compile assert_true: enumerable expected true got false
+PASS WebAssembly.compile: name
+PASS WebAssembly.compile: length
+FAIL WebAssembly.instantiate assert_true: enumerable expected true got false
+PASS WebAssembly.instantiate: name
+PASS WebAssembly.instantiate: length
+FAIL WebAssembly.Module.exports assert_true: enumerable expected true got false
+PASS WebAssembly.Module.exports: name
+PASS WebAssembly.Module.exports: length
+FAIL WebAssembly.Module.imports assert_true: enumerable expected true got false
+PASS WebAssembly.Module.imports: name
+PASS WebAssembly.Module.imports: length
+FAIL WebAssembly.Module.customSections assert_true: enumerable expected true got false
+PASS WebAssembly.Module.customSections: name
+PASS WebAssembly.Module.customSections: length
+FAIL WebAssembly.Instance.exports assert_true: enumerable expected true got false
+PASS WebAssembly.Instance.exports: getter
+PASS WebAssembly.Instance.exports: setter
+FAIL WebAssembly.Memory.grow assert_true: enumerable expected true got false
+PASS WebAssembly.Memory.grow: name
+PASS WebAssembly.Memory.grow: length
+FAIL WebAssembly.Memory.buffer assert_true: enumerable expected true got false
+PASS WebAssembly.Memory.buffer: getter
+PASS WebAssembly.Memory.buffer: setter
+FAIL WebAssembly.Table.grow assert_true: enumerable expected true got false
+PASS WebAssembly.Table.grow: name
+PASS WebAssembly.Table.grow: length
+FAIL WebAssembly.Table.get assert_true: enumerable expected true got false
+PASS WebAssembly.Table.get: name
+PASS WebAssembly.Table.get: length
+FAIL WebAssembly.Table.set assert_true: enumerable expected true got false
+PASS WebAssembly.Table.set: name
+PASS WebAssembly.Table.set: length
+FAIL WebAssembly.Table.length assert_true: enumerable expected true got false
+PASS WebAssembly.Table.length: getter
+PASS WebAssembly.Table.length: setter
+FAIL WebAssembly.Global.valueOf assert_true: enumerable expected true got false
+PASS WebAssembly.Global.valueOf: name
+PASS WebAssembly.Global.valueOf: length
+FAIL WebAssembly.Global.value assert_true: enumerable expected true got false
+PASS WebAssembly.Global.value: getter
+PASS WebAssembly.Global.value: setter
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any-expected.txt
new file mode 100644
index 0000000..884d6700
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS name
+PASS length
+PASS No arguments
+PASS Calling
+FAIL Empty descriptor assert_throws: function "() => new WebAssembly.Memory({})" did not throw
+FAIL Undefined initial value in descriptor assert_throws: function "() => new WebAssembly.Memory({ "initial": undefined })" did not throw
+FAIL Out-of-range initial value in descriptor: NaN assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" did not throw
+FAIL Out-of-range maximum value in descriptor: NaN assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" did not throw
+FAIL Out-of-range initial value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 9223372036854775807 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 9223372036854775807 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -1 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -1 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 4294967296 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 4294967296 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 68719476736 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 68719476736 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Proxy descriptor assert_unreached: Should not call [[HasProperty]] with maximum Reached unreachable code
+PASS Prototype
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.js
new file mode 100644
index 0000000..33256f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.js
@@ -0,0 +1,71 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/assertions.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_function_name(WebAssembly.Memory, "Memory", "WebAssembly.Memory");
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Memory, 1, "WebAssembly.Memory");
+}, "length");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Memory());
+}, "No arguments");
+
+test(() => {
+  const argument = { "initial": 0 };
+  assert_throws(new TypeError(), () => WebAssembly.Memory(argument));
+}, "Calling");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Memory({}));
+}, "Empty descriptor");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": undefined }));
+}, "Undefined initial value in descriptor");
+
+const outOfRangeValues = [
+  NaN,
+  Infinity,
+  -Infinity,
+  -1,
+  0x100000000,
+  0x1000000000,
+];
+
+for (const value of outOfRangeValues) {
+  test(() => {
+    assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": value }));
+  }, `Out-of-range initial value in descriptor: ${format_value(value)}`);
+
+  test(() => {
+    assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": 0, "maximum": value }));
+  }, `Out-of-range maximum value in descriptor: ${format_value(value)}`);
+}
+
+test(() => {
+  const proxy = new Proxy({}, {
+    has(o, x) {
+      assert_unreached(`Should not call [[HasProperty]] with ${x}`);
+    },
+    get(o, x) {
+      return 0;
+    },
+  });
+  new WebAssembly.Memory(proxy);
+}, "Proxy descriptor");
+
+test(() => {
+  const argument = { "initial": 0 };
+  const memory = new WebAssembly.Memory(argument);
+  assert_equals(Object.getPrototypeOf(memory), WebAssembly.Memory.prototype);
+}, "Prototype");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.worker-expected.txt
new file mode 100644
index 0000000..884d6700
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/memory/constructor.any.worker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+PASS name
+PASS length
+PASS No arguments
+PASS Calling
+FAIL Empty descriptor assert_throws: function "() => new WebAssembly.Memory({})" did not throw
+FAIL Undefined initial value in descriptor assert_throws: function "() => new WebAssembly.Memory({ "initial": undefined })" did not throw
+FAIL Out-of-range initial value in descriptor: NaN assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" did not throw
+FAIL Out-of-range maximum value in descriptor: NaN assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" did not throw
+FAIL Out-of-range initial value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 9223372036854775807 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 9223372036854775807 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -1 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -1 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 4294967296 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 4294967296 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Memory({ "initial": value })" threw object "RangeError: WebAssembly.Memory(): Property value 68719476736 is above the upper bound 32767" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Memory({ "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Memory(): Property value 68719476736 is above the upper bound 65536" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Proxy descriptor assert_unreached: Should not call [[HasProperty]] with maximum Reached unreachable code
+PASS Prototype
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/constructor.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/constructor.any.js
new file mode 100644
index 0000000..0f5eecf9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/constructor.any.js
@@ -0,0 +1,35 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/assertions.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_function_name(WebAssembly.Module, "Module", "WebAssembly.Module");
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Module, 1, "WebAssembly.Module");
+}, "length");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Module());
+}, "No arguments");
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module(emptyModuleBinary));
+}, "Calling");
+
+test(() => {
+  const buffer = new Uint8Array();
+  assert_throws(new WebAssembly.CompileError(), () => new WebAssembly.Module(buffer));
+}, "Empty buffer");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype);
+}, "Prototype");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any-expected.txt
new file mode 100644
index 0000000..b2e39b8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Missing arguments assert_throws: function "() => WebAssembly.Module.customSections(module)" did not throw
+PASS Non-Module arguments
+PASS Branding
+PASS Empty module
+PASS Empty module: array caching
+FAIL Custom sections WebAssembly.Module(): Wasm decoding failed: unexpected section: name @+33
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.js
new file mode 100644
index 0000000..146aa7fd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.js
@@ -0,0 +1,104 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+function assert_ArrayBuffer(buffer, expected) {
+  assert_equals(Object.getPrototypeOf(buffer), ArrayBuffer.prototype, "Prototype");
+  assert_array_equals(new Uint8Array(buffer), expected);
+}
+
+function assert_sections(sections, expected) {
+  assert_true(Array.isArray(sections), "Should be array");
+  assert_equals(Object.getPrototypeOf(sections), Array.prototype, "Prototype");
+
+  assert_equals(sections.length, expected.length);
+  for (let i = 0; i < expected.length; ++i) {
+    assert_ArrayBuffer(sections[i], expected[i]);
+  }
+}
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections());
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections(module));
+}, "Missing arguments");
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections({}, ""));
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections("", ""));
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections(undefined, ""));
+  assert_throws(new TypeError(), () => WebAssembly.Module.customSections(null, ""));
+}, "Non-Module arguments");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const fn = WebAssembly.Module.customSections;
+  const thisValues = [
+    undefined,
+    null,
+    true,
+    "",
+    Symbol(),
+    1,
+    {},
+    WebAssembly.Module,
+    WebAssembly.Module.prototype,
+  ];
+  for (const thisValue of thisValues) {
+    assert_sections(fn.call(thisValue, module, ""), []);
+  }
+}, "Branding");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_sections(WebAssembly.Module.customSections(module, ""), []);
+}, "Empty module");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_not_equals(WebAssembly.Module.customSections(module, ""),
+                    WebAssembly.Module.customSections(module, ""));
+}, "Empty module: array caching");
+
+test(() => {
+  const bytes1 = [87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121];
+  const bytes2 = [74, 83, 65, 80, 73];
+
+  const binary = new Binary;
+  binary.emit_section(kUnknownSectionCode, section => {
+    section.emit_string("name");
+    section.emit_bytes(bytes1);
+  });
+  binary.emit_section(kUnknownSectionCode, section => {
+    section.emit_string("name");
+    section.emit_bytes(bytes2);
+  });
+  binary.emit_section(kUnknownSectionCode, section => {
+    section.emit_string("foo");
+    section.emit_bytes(bytes1);
+  });
+
+  const builder = new WasmModuleBuilder();
+  builder.addExplicitSection(binary);
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+
+  assert_sections(WebAssembly.Module.customSections(module, "name"), [
+    bytes1,
+    bytes2,
+  ])
+
+  assert_sections(WebAssembly.Module.customSections(module, "foo"), [
+    bytes1,
+  ])
+
+  assert_sections(WebAssembly.Module.customSections(module, ""), [])
+  assert_sections(WebAssembly.Module.customSections(module, "\0"), [])
+  assert_sections(WebAssembly.Module.customSections(module, "name\0"), [])
+  assert_sections(WebAssembly.Module.customSections(module, "foo\0"), [])
+}, "Custom sections");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.worker-expected.txt
new file mode 100644
index 0000000..b2e39b8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/customSections.any.worker-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Missing arguments assert_throws: function "() => WebAssembly.Module.customSections(module)" did not throw
+PASS Non-Module arguments
+PASS Branding
+PASS Empty module
+PASS Empty module: array caching
+FAIL Custom sections WebAssembly.Module(): Wasm decoding failed: unexpected section: name @+33
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/exports.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/exports.any.js
new file mode 100644
index 0000000..c7ecdcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/exports.any.js
@@ -0,0 +1,121 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.exports());
+}, "Missing arguments");
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.exports({}));
+  assert_throws(new TypeError(), () => WebAssembly.Module.exports(""));
+  assert_throws(new TypeError(), () => WebAssembly.Module.exports(undefined));
+  assert_throws(new TypeError(), () => WebAssembly.Module.exports(null));
+}, "Non-Module arguments");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const fn = WebAssembly.Module.exports;
+  const thisValues = [
+    undefined,
+    null,
+    true,
+    "",
+    Symbol(),
+    1,
+    {},
+    WebAssembly.Module,
+    WebAssembly.Module.prototype,
+  ];
+  for (const thisValue of thisValues) {
+    assert_array_equals(fn.call(thisValue, module), []);
+  }
+}, "Branding");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const exports = WebAssembly.Module.exports(module);
+  assert_true(Array.isArray(exports));
+}, "Return type");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const exports = WebAssembly.Module.exports(module);
+  assert_true(Array.isArray(exports), "Should be array");
+  assert_equals(Object.getPrototypeOf(exports), Array.prototype, "Prototype");
+  assert_array_equals(exports, []);
+}, "Empty module");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_not_equals(WebAssembly.Module.exports(module), WebAssembly.Module.exports(module));
+}, "Empty module: array caching");
+
+function assert_ModuleExportDescriptor(export_, expected) {
+  assert_equals(Object.getPrototypeOf(export_), Object.prototype, "Prototype");
+
+  const name = Object.getOwnPropertyDescriptor(export_, "name");
+  assert_true(name.writable, "name: writable");
+  assert_true(name.enumerable, "name: enumerable");
+  assert_true(name.configurable, "name: configurable");
+  assert_equals(name.value, expected.name);
+
+  const kind = Object.getOwnPropertyDescriptor(export_, "kind");
+  assert_true(kind.writable, "kind: writable");
+  assert_true(kind.enumerable, "kind: enumerable");
+  assert_true(kind.configurable, "kind: configurable");
+  assert_equals(kind.value, expected.kind);
+}
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder
+    .addFunction("fn", kSig_v_v)
+    .addBody([
+        kExprEnd
+    ])
+    .exportFunc();
+  builder
+    .addFunction("fn2", kSig_v_v)
+    .addBody([
+        kExprEnd
+    ])
+    .exportFunc();
+
+  builder.setFunctionTableLength(1);
+  builder.addExportOfKind("table", kExternalTable, 0);
+
+  builder.addGlobal(kWasmI32, true)
+    .exportAs("global")
+    .init = 7;
+  builder.addGlobal(kWasmF64, true)
+    .exportAs("global2")
+    .init = 1.2;
+
+  builder.addMemory(0, 256, true);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const exports = WebAssembly.Module.exports(module);
+  assert_true(Array.isArray(exports), "Should be array");
+  assert_equals(Object.getPrototypeOf(exports), Array.prototype, "Prototype");
+
+  const expected = [
+    { "kind": "function", "name": "fn" },
+    { "kind": "function", "name": "fn2" },
+    { "kind": "table", "name": "table" },
+    { "kind": "global", "name": "global" },
+    { "kind": "global", "name": "global2" },
+    { "kind": "memory", "name": "memory" },
+  ];
+  assert_equals(exports.length, expected.length);
+  for (let i = 0; i < expected.length; ++i) {
+    assert_ModuleExportDescriptor(exports[i], expected[i]);
+  }
+}, "exports");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/imports.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/imports.any.js
new file mode 100644
index 0000000..522b262
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/module/imports.any.js
@@ -0,0 +1,105 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.imports());
+}, "Missing arguments");
+
+test(() => {
+  assert_throws(new TypeError(), () => WebAssembly.Module.imports({}));
+  assert_throws(new TypeError(), () => WebAssembly.Module.imports(""));
+  assert_throws(new TypeError(), () => WebAssembly.Module.imports(undefined));
+  assert_throws(new TypeError(), () => WebAssembly.Module.imports(null));
+}, "Non-Module arguments");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const fn = WebAssembly.Module.imports;
+  const thisValues = [
+    undefined,
+    null,
+    true,
+    "",
+    Symbol(),
+    1,
+    {},
+    WebAssembly.Module,
+    WebAssembly.Module.prototype,
+  ];
+  for (const thisValue of thisValues) {
+    assert_array_equals(fn.call(thisValue, module), []);
+  }
+}, "Branding");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const imports = WebAssembly.Module.imports(module);
+  assert_true(Array.isArray(imports));
+}, "Return type");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const imports = WebAssembly.Module.imports(module);
+  assert_true(Array.isArray(imports), "Should be array");
+  assert_equals(Object.getPrototypeOf(imports), Array.prototype, "Prototype");
+  assert_array_equals(imports, []);
+}, "Empty module");
+
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  assert_not_equals(WebAssembly.Module.imports(module), WebAssembly.Module.imports(module));
+}, "Empty module: array caching");
+
+function assert_ModuleImportDescriptor(import_, expected) {
+  assert_equals(Object.getPrototypeOf(import_), Object.prototype, "Prototype");
+
+  const module = Object.getOwnPropertyDescriptor(import_, "module");
+  assert_true(module.writable, "module: writable");
+  assert_true(module.enumerable, "module: enumerable");
+  assert_true(module.configurable, "module: configurable");
+  assert_equals(module.value, expected.module);
+
+  const name = Object.getOwnPropertyDescriptor(import_, "name");
+  assert_true(name.writable, "name: writable");
+  assert_true(name.enumerable, "name: enumerable");
+  assert_true(name.configurable, "name: configurable");
+  assert_equals(name.value, expected.name);
+
+  const kind = Object.getOwnPropertyDescriptor(import_, "kind");
+  assert_true(kind.writable, "kind: writable");
+  assert_true(kind.enumerable, "kind: enumerable");
+  assert_true(kind.configurable, "kind: configurable");
+  assert_equals(kind.value, expected.kind);
+}
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addImport("module", "fn", kSig_v_v);
+  builder.addImportedGlobal("module", "global", kWasmI32);
+  builder.addImportedMemory("module", "memory", 0, 128);
+  builder.addImportedTable("module", "table", 0, 128);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const imports = WebAssembly.Module.imports(module);
+  assert_true(Array.isArray(imports), "Should be array");
+  assert_equals(Object.getPrototypeOf(imports), Array.prototype, "Prototype");
+
+  const expected = [
+    { "module": "module", "kind": "function", "name": "fn" },
+    { "module": "module", "kind": "global", "name": "global" },
+    { "module": "module", "kind": "memory", "name": "memory" },
+    { "module": "module", "kind": "table", "name": "table" },
+  ];
+  assert_equals(imports.length, expected.length);
+  for (let i = 0; i < expected.length; ++i) {
+    assert_ModuleImportDescriptor(imports[i], expected[i]);
+  }
+}, "imports");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any-expected.txt
new file mode 100644
index 0000000..6592666
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS name
+PASS length
+PASS No arguments
+PASS Calling
+PASS Empty descriptor
+FAIL Undefined initial value in descriptor assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined })" did not throw
+PASS Undefined element value in descriptor
+FAIL Out-of-range initial value in descriptor: NaN assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" did not throw
+FAIL Out-of-range maximum value in descriptor: NaN assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" did not throw
+FAIL Out-of-range initial value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 9223372036854775807 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 9223372036854775807 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -1 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -1 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 4294967296 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 4294967296 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 68719476736 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 68719476736 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Proxy descriptor assert_unreached: Should not call [[HasProperty]] with maximum Reached unreachable code
+PASS Prototype
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.js
new file mode 100644
index 0000000..4aeac10
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.js
@@ -0,0 +1,83 @@
+// META: global=jsshell
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+// META: script=/wasm/jsapi/assertions.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+test(() => {
+  assert_function_name(WebAssembly.Table, "Table", "WebAssembly.Table");
+}, "name");
+
+test(() => {
+  assert_function_length(WebAssembly.Table, 1, "WebAssembly.Table");
+}, "length");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Table());
+}, "No arguments");
+
+test(() => {
+  const argument = { "initial": 0 };
+  assert_throws(new TypeError(), () => WebAssembly.Table(argument));
+}, "Calling");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Table({}));
+}, "Empty descriptor");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined }));
+}, "Undefined initial value in descriptor");
+
+test(() => {
+  assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": undefined, "initial": 0 }));
+}, "Undefined element value in descriptor");
+
+const outOfRangeValues = [
+  NaN,
+  Infinity,
+  -Infinity,
+  -1,
+  0x100000000,
+  0x1000000000,
+];
+
+for (const value of outOfRangeValues) {
+  test(() => {
+    assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": value }));
+  }, `Out-of-range initial value in descriptor: ${format_value(value)}`);
+
+  test(() => {
+    assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value }));
+  }, `Out-of-range maximum value in descriptor: ${format_value(value)}`);
+}
+
+test(() => {
+  const proxy = new Proxy({}, {
+    has(o, x) {
+      assert_unreached(`Should not call [[HasProperty]] with ${x}`);
+    },
+    get(o, x) {
+      switch (x) {
+      case "element":
+        return "anyfunc";
+      case "initial":
+      case "maximum":
+        return 0;
+      default:
+        return undefined;
+      }
+    },
+  });
+  new WebAssembly.Table(proxy);
+}, "Proxy descriptor");
+
+test(() => {
+  const argument = { "element": "anyfunc", "initial": 0 };
+  const table = new WebAssembly.Table(argument);
+  assert_equals(Object.getPrototypeOf(table), WebAssembly.Table.prototype);
+}, "Prototype");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.worker-expected.txt
new file mode 100644
index 0000000..6592666
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/table/constructor.any.worker-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS name
+PASS length
+PASS No arguments
+PASS Calling
+PASS Empty descriptor
+FAIL Undefined initial value in descriptor assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined })" did not throw
+PASS Undefined element value in descriptor
+FAIL Out-of-range initial value in descriptor: NaN assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" did not throw
+FAIL Out-of-range maximum value in descriptor: NaN assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" did not throw
+FAIL Out-of-range initial value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 9223372036854775807 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 9223372036854775807 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -Infinity assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value -9223372036854775808 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: -1 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: -1 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value -1 is below the lower bound 0" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 4294967296 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 4294967296 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 4294967296 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range initial value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": value })" threw object "RangeError: WebAssembly.Module(): Property value 68719476736 is above the upper bound 10000000" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Out-of-range maximum value in descriptor: 68719476736 assert_throws: function "() => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })" threw object "RangeError: WebAssembly.Module(): Property value 68719476736 is above the upper bound 4294967295" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL Proxy descriptor assert_unreached: Should not call [[HasProperty]] with maximum Reached unreachable code
+PASS Prototype
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-constants.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-constants.js
new file mode 100644
index 0000000..f056f9c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-constants.js
@@ -0,0 +1,374 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-wasm
+
+function bytes() {
+  var buffer = new ArrayBuffer(arguments.length);
+  var view = new Uint8Array(buffer);
+  for (var i = 0; i < arguments.length; i++) {
+    var val = arguments[i];
+    if ((typeof val) == "string") val = val.charCodeAt(0);
+    view[i] = val | 0;
+  }
+  return buffer;
+}
+
+// Header declaration constants
+var kWasmH0 = 0;
+var kWasmH1 = 0x61;
+var kWasmH2 = 0x73;
+var kWasmH3 = 0x6d;
+
+var kWasmV0 = 1;
+var kWasmV1 = 0;
+var kWasmV2 = 0;
+var kWasmV3 = 0;
+
+var kHeaderSize = 8;
+var kPageSize = 65536;
+
+function bytesWithHeader() {
+  var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
+  var view = new Uint8Array(buffer);
+  view[0] = kWasmH0;
+  view[1] = kWasmH1;
+  view[2] = kWasmH2;
+  view[3] = kWasmH3;
+  view[4] = kWasmV0;
+  view[5] = kWasmV1;
+  view[6] = kWasmV2;
+  view[7] = kWasmV3;
+  for (var i = 0; i < arguments.length; i++) {
+    var val = arguments[i];
+    if ((typeof val) == "string") val = val.charCodeAt(0);
+    view[kHeaderSize + i] = val | 0;
+  }
+  return buffer;
+}
+
+let kDeclNoLocals = 0;
+
+// Section declaration constants
+let kUnknownSectionCode = 0;
+let kTypeSectionCode = 1;      // Function signature declarations
+let kImportSectionCode = 2;    // Import declarations
+let kFunctionSectionCode = 3;  // Function declarations
+let kTableSectionCode = 4;     // Indirect function table and other tables
+let kMemorySectionCode = 5;    // Memory attributes
+let kGlobalSectionCode = 6;    // Global declarations
+let kExportSectionCode = 7;    // Exports
+let kStartSectionCode = 8;     // Start function declaration
+let kElementSectionCode = 9;  // Elements section
+let kCodeSectionCode = 10;      // Function code
+let kDataSectionCode = 11;     // Data segments
+let kNameSectionCode = 12;     // Name section (encoded as string)
+
+let kWasmFunctionTypeForm = 0x60;
+let kWasmAnyFunctionTypeForm = 0x70;
+
+let kResizableMaximumFlag = 1;
+
+// Function declaration flags
+let kDeclFunctionName   = 0x01;
+let kDeclFunctionImport = 0x02;
+let kDeclFunctionLocals = 0x04;
+let kDeclFunctionExport = 0x08;
+
+// Local types
+let kWasmStmt = 0x40;
+let kWasmI32 = 0x7f;
+let kWasmI64 = 0x7e;
+let kWasmF32 = 0x7d;
+let kWasmF64 = 0x7c;
+let kWasmS128 = 0x7b;
+
+let kExternalFunction = 0;
+let kExternalTable = 1;
+let kExternalMemory = 2;
+let kExternalGlobal = 3;
+
+let kTableZero = 0;
+let kMemoryZero = 0;
+
+// Useful signatures
+let kSig_i_i = makeSig([kWasmI32], [kWasmI32]);
+let kSig_l_l = makeSig([kWasmI64], [kWasmI64]);
+let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
+let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
+let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
+let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]);
+let kSig_v_v = makeSig([], []);
+let kSig_i_v = makeSig([], [kWasmI32]);
+let kSig_l_v = makeSig([], [kWasmI64]);
+let kSig_f_v = makeSig([], [kWasmF64]);
+let kSig_d_v = makeSig([], [kWasmF64]);
+let kSig_v_i = makeSig([kWasmI32], []);
+let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []);
+let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []);
+let kSig_v_l = makeSig([kWasmI64], []);
+let kSig_v_d = makeSig([kWasmF64], []);
+let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []);
+let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
+let kSig_s_v = makeSig([], [kWasmS128]);
+
+function makeSig(params, results) {
+  return {params: params, results: results};
+}
+
+function makeSig_v_x(x) {
+  return makeSig([x], []);
+}
+
+function makeSig_v_xx(x) {
+  return makeSig([x, x], []);
+}
+
+function makeSig_r_v(r) {
+  return makeSig([], [r]);
+}
+
+function makeSig_r_x(r, x) {
+  return makeSig([x], [r]);
+}
+
+function makeSig_r_xx(r, x) {
+  return makeSig([x, x], [r]);
+}
+
+// Opcodes
+let kExprUnreachable = 0x00;
+let kExprNop = 0x01;
+let kExprBlock = 0x02;
+let kExprLoop = 0x03;
+let kExprIf = 0x04;
+let kExprElse = 0x05;
+let kExprTry = 0x06;
+let kExprCatch = 0x07;
+let kExprThrow = 0x08;
+let kExprEnd = 0x0b;
+let kExprBr = 0x0c;
+let kExprBrIf = 0x0d;
+let kExprBrTable = 0x0e;
+let kExprReturn = 0x0f;
+let kExprCallFunction = 0x10;
+let kExprCallIndirect = 0x11;
+let kExprDrop = 0x1a;
+let kExprSelect = 0x1b;
+let kExprGetLocal = 0x20;
+let kExprSetLocal = 0x21;
+let kExprTeeLocal = 0x22;
+let kExprGetGlobal = 0x23;
+let kExprSetGlobal = 0x24;
+let kExprI32Const = 0x41;
+let kExprI64Const = 0x42;
+let kExprF32Const = 0x43;
+let kExprF64Const = 0x44;
+let kExprI32LoadMem = 0x28;
+let kExprI64LoadMem = 0x29;
+let kExprF32LoadMem = 0x2a;
+let kExprF64LoadMem = 0x2b;
+let kExprI32LoadMem8S = 0x2c;
+let kExprI32LoadMem8U = 0x2d;
+let kExprI32LoadMem16S = 0x2e;
+let kExprI32LoadMem16U = 0x2f;
+let kExprI64LoadMem8S = 0x30;
+let kExprI64LoadMem8U = 0x31;
+let kExprI64LoadMem16S = 0x32;
+let kExprI64LoadMem16U = 0x33;
+let kExprI64LoadMem32S = 0x34;
+let kExprI64LoadMem32U = 0x35;
+let kExprI32StoreMem = 0x36;
+let kExprI64StoreMem = 0x37;
+let kExprF32StoreMem = 0x38;
+let kExprF64StoreMem = 0x39;
+let kExprI32StoreMem8 = 0x3a;
+let kExprI32StoreMem16 = 0x3b;
+let kExprI64StoreMem8 = 0x3c;
+let kExprI64StoreMem16 = 0x3d;
+let kExprI64StoreMem32 = 0x3e;
+let kExprMemorySize = 0x3f;
+let kExprGrowMemory = 0x40;
+let kExprI32Eqz = 0x45;
+let kExprI32Eq = 0x46;
+let kExprI32Ne = 0x47;
+let kExprI32LtS = 0x48;
+let kExprI32LtU = 0x49;
+let kExprI32GtS = 0x4a;
+let kExprI32GtU = 0x4b;
+let kExprI32LeS = 0x4c;
+let kExprI32LeU = 0x4d;
+let kExprI32GeS = 0x4e;
+let kExprI32GeU = 0x4f;
+let kExprI64Eqz = 0x50;
+let kExprI64Eq = 0x51;
+let kExprI64Ne = 0x52;
+let kExprI64LtS = 0x53;
+let kExprI64LtU = 0x54;
+let kExprI64GtS = 0x55;
+let kExprI64GtU = 0x56;
+let kExprI64LeS = 0x57;
+let kExprI64LeU = 0x58;
+let kExprI64GeS = 0x59;
+let kExprI64GeU = 0x5a;
+let kExprF32Eq = 0x5b;
+let kExprF32Ne = 0x5c;
+let kExprF32Lt = 0x5d;
+let kExprF32Gt = 0x5e;
+let kExprF32Le = 0x5f;
+let kExprF32Ge = 0x60;
+let kExprF64Eq = 0x61;
+let kExprF64Ne = 0x62;
+let kExprF64Lt = 0x63;
+let kExprF64Gt = 0x64;
+let kExprF64Le = 0x65;
+let kExprF64Ge = 0x66;
+let kExprI32Clz = 0x67;
+let kExprI32Ctz = 0x68;
+let kExprI32Popcnt = 0x69;
+let kExprI32Add = 0x6a;
+let kExprI32Sub = 0x6b;
+let kExprI32Mul = 0x6c;
+let kExprI32DivS = 0x6d;
+let kExprI32DivU = 0x6e;
+let kExprI32RemS = 0x6f;
+let kExprI32RemU = 0x70;
+let kExprI32And = 0x71;
+let kExprI32Ior = 0x72;
+let kExprI32Xor = 0x73;
+let kExprI32Shl = 0x74;
+let kExprI32ShrS = 0x75;
+let kExprI32ShrU = 0x76;
+let kExprI32Rol = 0x77;
+let kExprI32Ror = 0x78;
+let kExprI64Clz = 0x79;
+let kExprI64Ctz = 0x7a;
+let kExprI64Popcnt = 0x7b;
+let kExprI64Add = 0x7c;
+let kExprI64Sub = 0x7d;
+let kExprI64Mul = 0x7e;
+let kExprI64DivS = 0x7f;
+let kExprI64DivU = 0x80;
+let kExprI64RemS = 0x81;
+let kExprI64RemU = 0x82;
+let kExprI64And = 0x83;
+let kExprI64Ior = 0x84;
+let kExprI64Xor = 0x85;
+let kExprI64Shl = 0x86;
+let kExprI64ShrS = 0x87;
+let kExprI64ShrU = 0x88;
+let kExprI64Rol = 0x89;
+let kExprI64Ror = 0x8a;
+let kExprF32Abs = 0x8b;
+let kExprF32Neg = 0x8c;
+let kExprF32Ceil = 0x8d;
+let kExprF32Floor = 0x8e;
+let kExprF32Trunc = 0x8f;
+let kExprF32NearestInt = 0x90;
+let kExprF32Sqrt = 0x91;
+let kExprF32Add = 0x92;
+let kExprF32Sub = 0x93;
+let kExprF32Mul = 0x94;
+let kExprF32Div = 0x95;
+let kExprF32Min = 0x96;
+let kExprF32Max = 0x97;
+let kExprF32CopySign = 0x98;
+let kExprF64Abs = 0x99;
+let kExprF64Neg = 0x9a;
+let kExprF64Ceil = 0x9b;
+let kExprF64Floor = 0x9c;
+let kExprF64Trunc = 0x9d;
+let kExprF64NearestInt = 0x9e;
+let kExprF64Sqrt = 0x9f;
+let kExprF64Add = 0xa0;
+let kExprF64Sub = 0xa1;
+let kExprF64Mul = 0xa2;
+let kExprF64Div = 0xa3;
+let kExprF64Min = 0xa4;
+let kExprF64Max = 0xa5;
+let kExprF64CopySign = 0xa6;
+let kExprI32ConvertI64 = 0xa7;
+let kExprI32SConvertF32 = 0xa8;
+let kExprI32UConvertF32 = 0xa9;
+let kExprI32SConvertF64 = 0xaa;
+let kExprI32UConvertF64 = 0xab;
+let kExprI64SConvertI32 = 0xac;
+let kExprI64UConvertI32 = 0xad;
+let kExprI64SConvertF32 = 0xae;
+let kExprI64UConvertF32 = 0xaf;
+let kExprI64SConvertF64 = 0xb0;
+let kExprI64UConvertF64 = 0xb1;
+let kExprF32SConvertI32 = 0xb2;
+let kExprF32UConvertI32 = 0xb3;
+let kExprF32SConvertI64 = 0xb4;
+let kExprF32UConvertI64 = 0xb5;
+let kExprF32ConvertF64 = 0xb6;
+let kExprF64SConvertI32 = 0xb7;
+let kExprF64UConvertI32 = 0xb8;
+let kExprF64SConvertI64 = 0xb9;
+let kExprF64UConvertI64 = 0xba;
+let kExprF64ConvertF32 = 0xbb;
+let kExprI32ReinterpretF32 = 0xbc;
+let kExprI64ReinterpretF64 = 0xbd;
+let kExprF32ReinterpretI32 = 0xbe;
+let kExprF64ReinterpretI64 = 0xbf;
+
+let kTrapUnreachable          = 0;
+let kTrapMemOutOfBounds       = 1;
+let kTrapDivByZero            = 2;
+let kTrapDivUnrepresentable   = 3;
+let kTrapRemByZero            = 4;
+let kTrapFloatUnrepresentable = 5;
+let kTrapFuncInvalid          = 6;
+let kTrapFuncSigMismatch      = 7;
+let kTrapInvalidIndex         = 8;
+
+let kTrapMsgs = [
+  "unreachable",
+  "memory access out of bounds",
+  "divide by zero",
+  "divide result unrepresentable",
+  "remainder by zero",
+  "integer result unrepresentable",
+  "invalid function",
+  "function signature mismatch",
+  "invalid index into function table"
+];
+
+function assertTraps(trap, code) {
+    var threwException = true;
+    try {
+      if (typeof code === 'function') {
+        code();
+      } else {
+        eval(code);
+      }
+      threwException = false;
+    } catch (e) {
+      assertEquals("object", typeof e);
+      assertEquals(kTrapMsgs[trap], e.message);
+      // Success.
+      return;
+    }
+    throw new MjsUnitAssertionError("Did not trap, expected: " + kTrapMsgs[trap]);
+}
+
+function assertWasmThrows(value, code) {
+    assertEquals("number", typeof(value));
+    try {
+      if (typeof code === 'function') {
+        code();
+      } else {
+        eval(code);
+      }
+    } catch (e) {
+      assertEquals("number", typeof e);
+      assertEquals(value, e);
+      // Success.
+      return;
+    }
+    throw new MjsUnitAssertionError("Did not throw at all, expected: " + value);
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-module-builder.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-module-builder.js
new file mode 100644
index 0000000..6e9284e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/jsapi/wasm-module-builder.js
@@ -0,0 +1,555 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Used for encoding f32 and double constants to bits.
+let __buffer = new ArrayBuffer(8);
+let byte_view = new Int8Array(__buffer);
+let f32_view = new Float32Array(__buffer);
+let f64_view = new Float64Array(__buffer);
+
+class Binary extends Array {
+  emit_u8(val) {
+    this.push(val);
+  }
+
+  emit_u16(val) {
+    this.push(val & 0xff);
+    this.push((val >> 8) & 0xff);
+  }
+
+  emit_u32(val) {
+    this.push(val & 0xff);
+    this.push((val >> 8) & 0xff);
+    this.push((val >> 16) & 0xff);
+    this.push((val >> 24) & 0xff);
+  }
+
+  emit_u32v(val) {
+    while (true) {
+      let v = val & 0xff;
+      val = val >>> 7;
+      if (val == 0) {
+        this.push(v);
+        break;
+      }
+      this.push(v | 0x80);
+    }
+  }
+
+  emit_bytes(data) {
+    for (let i = 0; i < data.length; i++) {
+      this.push(data[i] & 0xff);
+    }
+  }
+
+  emit_string(string) {
+    // When testing illegal names, we pass a byte array directly.
+    if (string instanceof Array) {
+      this.emit_u32v(string.length);
+      this.emit_bytes(string);
+      return;
+    }
+
+    // This is the hacky way to convert a JavaScript string to a UTF8 encoded
+    // string only containing single-byte characters.
+    let string_utf8 = unescape(encodeURIComponent(string));
+    this.emit_u32v(string_utf8.length);
+    for (let i = 0; i < string_utf8.length; i++) {
+      this.emit_u8(string_utf8.charCodeAt(i));
+    }
+  }
+
+  emit_header() {
+    this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3,
+              kWasmV0, kWasmV1, kWasmV2, kWasmV3);
+  }
+
+  emit_section(section_code, content_generator) {
+    // Emit section name.
+    this.emit_u8(section_code);
+    // Emit the section to a temporary buffer: its full length isn't know yet.
+    let section = new Binary;
+    content_generator(section);
+    // Emit section length.
+    this.emit_u32v(section.length);
+    // Copy the temporary buffer.
+    this.push(...section);
+  }
+}
+
+class WasmFunctionBuilder {
+  constructor(module, name, type_index) {
+    this.module = module;
+    this.name = name;
+    this.type_index = type_index;
+    this.body = [];
+  }
+
+  exportAs(name) {
+    this.module.addExport(name, this.index);
+    return this;
+  }
+
+  exportFunc() {
+    this.exportAs(this.name);
+    return this;
+  }
+
+  addBody(body) {
+    this.body = body;
+    return this;
+  }
+
+  addLocals(locals) {
+    this.locals = locals;
+    return this;
+  }
+
+  end() {
+    return this.module;
+  }
+}
+
+class WasmGlobalBuilder {
+  constructor(module, type, mutable) {
+    this.module = module;
+    this.type = type;
+    this.mutable = mutable;
+    this.init = 0;
+  }
+
+  exportAs(name) {
+    this.module.exports.push({name: name, kind: kExternalGlobal,
+                              index: this.index});
+    return this;
+  }
+}
+
+class WasmModuleBuilder {
+  constructor() {
+    this.types = [];
+    this.imports = [];
+    this.exports = [];
+    this.globals = [];
+    this.functions = [];
+    this.function_table = [];
+    this.function_table_length = 0;
+    this.function_table_inits = [];
+    this.segments = [];
+    this.explicit = [];
+    this.num_imported_funcs = 0;
+    this.num_imported_globals = 0;
+    return this;
+  }
+
+  addStart(start_index) {
+    this.start_index = start_index;
+    return this;
+  }
+
+  addMemory(min, max, exp) {
+    this.memory = {min: min, max: max, exp: exp};
+    return this;
+  }
+
+  addExplicitSection(bytes) {
+    this.explicit.push(bytes);
+    return this;
+  }
+
+  addType(type) {
+    // TODO: canonicalize types?
+    this.types.push(type);
+    return this.types.length - 1;
+  }
+
+  addGlobal(local_type, mutable) {
+    let glob = new WasmGlobalBuilder(this, local_type, mutable);
+    glob.index = this.globals.length + this.num_imported_globals;
+    this.globals.push(glob);
+    return glob;
+  }
+
+  addFunction(name, type) {
+    let type_index = (typeof type) == "number" ? type : this.addType(type);
+    let func = new WasmFunctionBuilder(this, name, type_index);
+    func.index = this.functions.length + this.num_imported_funcs;
+    this.functions.push(func);
+    return func;
+  }
+
+  addImport(module = "", name, type) {
+    let type_index = (typeof type) == "number" ? type : this.addType(type);
+    this.imports.push({module: module, name: name, kind: kExternalFunction,
+                       type: type_index});
+    return this.num_imported_funcs++;
+  }
+
+  addImportedGlobal(module = "", name, type) {
+    let o = {module: module, name: name, kind: kExternalGlobal, type: type,
+             mutable: false}
+    this.imports.push(o);
+    return this.num_imported_globals++;
+  }
+
+  addImportedMemory(module = "", name, initial = 0, maximum) {
+    let o = {module: module, name: name, kind: kExternalMemory,
+             initial: initial, maximum: maximum};
+    this.imports.push(o);
+    return this;
+  }
+
+  addImportedTable(module = "", name, initial, maximum) {
+    let o = {module: module, name: name, kind: kExternalTable, initial: initial,
+             maximum: maximum};
+    this.imports.push(o);
+  }
+
+  addExport(name, index) {
+    this.exports.push({name: name, kind: kExternalFunction, index: index});
+    return this;
+  }
+
+  addExportOfKind(name, kind, index) {
+    this.exports.push({name: name, kind: kind, index: index});
+    return this;
+  }
+
+  addDataSegment(addr, data, is_global = false) {
+    this.segments.push({addr: addr, data: data, is_global: is_global});
+    return this.segments.length - 1;
+  }
+
+  exportMemoryAs(name) {
+    this.exports.push({name: name, kind: kExternalMemory, index: 0});
+  }
+
+  addFunctionTableInit(base, is_global, array) {
+    this.function_table_inits.push({base: base, is_global: is_global,
+                                    array: array});
+    if (!is_global) {
+      var length = base + array.length;
+      if (length > this.function_table_length) {
+        this.function_table_length = length;
+      }
+    }
+    return this;
+  }
+
+  appendToTable(array) {
+    return this.addFunctionTableInit(this.function_table.length, false, array);
+  }
+
+  setFunctionTableLength(length) {
+    this.function_table_length = length;
+    return this;
+  }
+
+  toArray(debug = false) {
+    let binary = new Binary;
+    let wasm = this;
+
+    // Add header
+    binary.emit_header();
+
+    // Add type section
+    if (wasm.types.length > 0) {
+      if (debug) print("emitting types @ " + binary.length);
+      binary.emit_section(kTypeSectionCode, section => {
+        section.emit_u32v(wasm.types.length);
+        for (let type of wasm.types) {
+          section.emit_u8(kWasmFunctionTypeForm);
+          section.emit_u32v(type.params.length);
+          for (let param of type.params) {
+            section.emit_u8(param);
+          }
+          section.emit_u32v(type.results.length);
+          for (let result of type.results) {
+            section.emit_u8(result);
+          }
+        }
+      });
+    }
+
+    // Add imports section
+    if (wasm.imports.length > 0) {
+      if (debug) print("emitting imports @ " + binary.length);
+      binary.emit_section(kImportSectionCode, section => {
+        section.emit_u32v(wasm.imports.length);
+        for (let imp of wasm.imports) {
+          section.emit_string(imp.module);
+          section.emit_string(imp.name || '');
+          section.emit_u8(imp.kind);
+          if (imp.kind == kExternalFunction) {
+            section.emit_u32v(imp.type);
+          } else if (imp.kind == kExternalGlobal) {
+            section.emit_u32v(imp.type);
+            section.emit_u8(imp.mutable);
+          } else if (imp.kind == kExternalMemory) {
+            var has_max = (typeof imp.maximum) != "undefined";
+            section.emit_u8(has_max ? 1 : 0); // flags
+            section.emit_u32v(imp.initial); // initial
+            if (has_max) section.emit_u32v(imp.maximum); // maximum
+          } else if (imp.kind == kExternalTable) {
+            section.emit_u8(kWasmAnyFunctionTypeForm);
+            var has_max = (typeof imp.maximum) != "undefined";
+            section.emit_u8(has_max ? 1 : 0); // flags
+            section.emit_u32v(imp.initial); // initial
+            if (has_max) section.emit_u32v(imp.maximum); // maximum
+          } else {
+            throw new Error("unknown/unsupported import kind " + imp.kind);
+          }
+        }
+      });
+    }
+
+    // Add functions declarations
+    let has_names = false;
+    let names = false;
+    if (wasm.functions.length > 0) {
+      if (debug) print("emitting function decls @ " + binary.length);
+      binary.emit_section(kFunctionSectionCode, section => {
+        section.emit_u32v(wasm.functions.length);
+        for (let func of wasm.functions) {
+          has_names = has_names || (func.name != undefined &&
+                                   func.name.length > 0);
+          section.emit_u32v(func.type_index);
+        }
+      });
+    }
+
+    // Add function_table.
+    if (wasm.function_table_length > 0) {
+      if (debug) print("emitting table @ " + binary.length);
+      binary.emit_section(kTableSectionCode, section => {
+        section.emit_u8(1);  // one table entry
+        section.emit_u8(kWasmAnyFunctionTypeForm);
+        section.emit_u8(1);
+        section.emit_u32v(wasm.function_table_length);
+        section.emit_u32v(wasm.function_table_length);
+      });
+    }
+
+    // Add memory section
+    if (wasm.memory != undefined) {
+      if (debug) print("emitting memory @ " + binary.length);
+      binary.emit_section(kMemorySectionCode, section => {
+        section.emit_u8(1);  // one memory entry
+        section.emit_u32v(kResizableMaximumFlag);
+        section.emit_u32v(wasm.memory.min);
+        section.emit_u32v(wasm.memory.max);
+      });
+    }
+
+    // Add global section.
+    if (wasm.globals.length > 0) {
+      if (debug) print ("emitting globals @ " + binary.length);
+      binary.emit_section(kGlobalSectionCode, section => {
+        section.emit_u32v(wasm.globals.length);
+        for (let global of wasm.globals) {
+          section.emit_u8(global.type);
+          section.emit_u8(global.mutable);
+          if ((typeof global.init_index) == "undefined") {
+            // Emit a constant initializer.
+            switch (global.type) {
+            case kWasmI32:
+              section.emit_u8(kExprI32Const);
+              section.emit_u32v(global.init);
+              break;
+            case kWasmI64:
+              section.emit_u8(kExprI64Const);
+              section.emit_u8(global.init);
+              break;
+            case kWasmF32:
+              section.emit_u8(kExprF32Const);
+              f32_view[0] = global.init;
+              section.emit_u8(byte_view[0]);
+              section.emit_u8(byte_view[1]);
+              section.emit_u8(byte_view[2]);
+              section.emit_u8(byte_view[3]);
+              break;
+            case kWasmF64:
+              section.emit_u8(kExprF64Const);
+              f64_view[0] = global.init;
+              section.emit_u8(byte_view[0]);
+              section.emit_u8(byte_view[1]);
+              section.emit_u8(byte_view[2]);
+              section.emit_u8(byte_view[3]);
+              section.emit_u8(byte_view[4]);
+              section.emit_u8(byte_view[5]);
+              section.emit_u8(byte_view[6]);
+              section.emit_u8(byte_view[7]);
+              break;
+            }
+          } else {
+            // Emit a global-index initializer.
+            section.emit_u8(kExprGetGlobal);
+            section.emit_u32v(global.init_index);
+          }
+          section.emit_u8(kExprEnd);  // end of init expression
+        }
+      });
+    }
+
+    // Add export table.
+    var mem_export = (wasm.memory != undefined && wasm.memory.exp);
+    var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
+    if (exports_count > 0) {
+      if (debug) print("emitting exports @ " + binary.length);
+      binary.emit_section(kExportSectionCode, section => {
+        section.emit_u32v(exports_count);
+        for (let exp of wasm.exports) {
+          section.emit_string(exp.name);
+          section.emit_u8(exp.kind);
+          section.emit_u32v(exp.index);
+        }
+        if (mem_export) {
+          section.emit_string("memory");
+          section.emit_u8(kExternalMemory);
+          section.emit_u8(0);
+        }
+      });
+    }
+
+    // Add start function section.
+    if (wasm.start_index != undefined) {
+      if (debug) print("emitting start function @ " + binary.length);
+      binary.emit_section(kStartSectionCode, section => {
+        section.emit_u32v(wasm.start_index);
+      });
+    }
+
+    // Add table elements.
+    if (wasm.function_table_inits.length > 0) {
+      if (debug) print("emitting table @ " + binary.length);
+      binary.emit_section(kElementSectionCode, section => {
+        var inits = wasm.function_table_inits;
+        section.emit_u32v(inits.length);
+        section.emit_u8(0); // table index
+
+        for (let init of inits) {
+          if (init.is_global) {
+            section.emit_u8(kExprGetGlobal);
+          } else {
+            section.emit_u8(kExprI32Const);
+          }
+          section.emit_u32v(init.base);
+          section.emit_u8(kExprEnd);
+          section.emit_u32v(init.array.length);
+          for (let index of init.array) {
+            section.emit_u32v(index);
+          }
+        }
+      });
+    }
+
+    // Add function bodies.
+    if (wasm.functions.length > 0) {
+      // emit function bodies
+      if (debug) print("emitting code @ " + binary.length);
+      binary.emit_section(kCodeSectionCode, section => {
+        section.emit_u32v(wasm.functions.length);
+        for (let func of wasm.functions) {
+          // Function body length will be patched later.
+          let local_decls = [];
+          let l = func.locals;
+          if (l != undefined) {
+            let local_decls_count = 0;
+            if (l.i32_count > 0) {
+              local_decls.push({count: l.i32_count, type: kWasmI32});
+            }
+            if (l.i64_count > 0) {
+              local_decls.push({count: l.i64_count, type: kWasmI64});
+            }
+            if (l.f32_count > 0) {
+              local_decls.push({count: l.f32_count, type: kWasmF32});
+            }
+            if (l.f64_count > 0) {
+              local_decls.push({count: l.f64_count, type: kWasmF64});
+            }
+          }
+
+          let header = new Binary;
+          header.emit_u32v(local_decls.length);
+          for (let decl of local_decls) {
+            header.emit_u32v(decl.count);
+            header.emit_u8(decl.type);
+          }
+
+          section.emit_u32v(header.length + func.body.length);
+          section.emit_bytes(header);
+          section.emit_bytes(func.body);
+        }
+      });
+    }
+
+    // Add data segments.
+    if (wasm.segments.length > 0) {
+      if (debug) print("emitting data segments @ " + binary.length);
+      binary.emit_section(kDataSectionCode, section => {
+        section.emit_u32v(wasm.segments.length);
+        for (let seg of wasm.segments) {
+          section.emit_u8(0);  // linear memory index 0
+          if (seg.is_global) {
+            // initializer is a global variable
+            section.emit_u8(kExprGetGlobal);
+            section.emit_u32v(seg.addr);
+          } else {
+            // initializer is a constant
+            section.emit_u8(kExprI32Const);
+            section.emit_u32v(seg.addr);
+          }
+          section.emit_u8(kExprEnd);
+          section.emit_u32v(seg.data.length);
+          section.emit_bytes(seg.data);
+        }
+      });
+    }
+
+    // Add any explicitly added sections
+    for (let exp of wasm.explicit) {
+      if (debug) print("emitting explicit @ " + binary.length);
+      binary.emit_bytes(exp);
+    }
+
+    // Add function names.
+    if (has_names) {
+      if (debug) print("emitting names @ " + binary.length);
+      binary.emit_section(kUnknownSectionCode, section => {
+        section.emit_string("name");
+        var count = wasm.functions.length + wasm.num_imported_funcs;
+        section.emit_u32v(count);
+        for (var i = 0; i < wasm.num_imported_funcs; i++) {
+          section.emit_u8(0); // empty string
+          section.emit_u8(0); // local names count == 0
+        }
+        for (let func of wasm.functions) {
+          var name = func.name == undefined ? "" : func.name;
+          section.emit_string(name);
+          section.emit_u8(0);  // local names count == 0
+        }
+      });
+    }
+
+    return binary;
+  }
+
+  toBuffer(debug = false) {
+    let bytes = this.toArray(debug);
+    let buffer = new ArrayBuffer(bytes.length);
+    let view = new Uint8Array(buffer);
+    for (let i = 0; i < bytes.length; i++) {
+      let val = bytes[i];
+      if ((typeof val) == "string") val = val.charCodeAt(0);
+      view[i] = val | 0;
+    }
+    return new Uint8Array(buffer);
+  }
+
+  instantiate(...args) {
+    let module = new WebAssembly.Module(this.toBuffer());
+    let instance = new WebAssembly.Instance(module, ...args);
+    return instance;
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_idb_worker.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_idb_worker.js
deleted file mode 100644
index 9d36d74..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_idb_worker.js
+++ /dev/null
@@ -1,26 +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.
-
-importScripts('/resources/testharness.js');
-importScripts('resources/load_wasm.js');
-importScripts('wasm_indexeddb_test.js');
-
-onmessage = function(e) {
-  if (e.data.command === "load") {
-    loadFromIndexedDB(e.data.db_name)
-      .then(res => {
-        if (res === 2) postMessage("ok");
-        else postMessage("error");
-      },
-            error => postMessage(error));
-  } else if (e.data.command === "save") {
-    createAndSaveToIndexedDB(e.data.db_name)
-      .then((m) => {
-        postMessage("ok");
-      },
-            () => postMessage("error"));
-  } else {
-    postMessage("unknown message: " + e.data);
-  }
-}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.https.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.https.html
deleted file mode 100644
index 320f046..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.https.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-<script src="resources/load_wasm.js"></script>
-<script src="wasm_indexeddb_test.js"></script>
-</head>
-<body>
-<script>
-  promise_test(TestIndexedDBLoadStoreSecure, "serialize/deserialize to IndexedDB ");
-  promise_test(SaveToIDBAndLoadInWorker, "Save to IDB and load in worker");
-  promise_test(SaveToIDBInWorkerAndLoadInMain, "Save in worker to IDB and load in window");
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js
deleted file mode 100644
index a5a582cd..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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.
-
-var db_name = "db_wasm_test";
-var obj_store = 'store';
-var module_key = 'my_module';
-
-function createAndSaveToIndexedDB(db_name) {
-  return createWasmModule()
-    .then(mod => new Promise((resolve, reject) => {
-      var delete_request = indexedDB.deleteDatabase(db_name);
-      delete_request.onsuccess = function() {
-        var open_request = indexedDB.open(db_name);
-        open_request.onupgradeneeded = function() {
-          var db = open_request.result;
-          db.createObjectStore(obj_store);
-        };
-        open_request.onsuccess = function() {
-          var db = open_request.result;
-          var tx = db.transaction(obj_store, 'readwrite');
-          var store = tx.objectStore(obj_store);
-          try {
-            store.put(mod, module_key);
-          } catch(e) {
-            db.close();
-            reject(e);
-            return;
-          }
-          tx.oncomplete = function() {
-            db.close();
-            resolve();
-            return;
-          };
-        };
-      };
-    }));
-}
-
-function loadFromIndexedDB(db_name) {
-  var open_request = indexedDB.open(db_name);
-
-  return new Promise((resolve, reject) => {
-    open_request.onsuccess = function() {
-      var db = open_request.result;
-      var tx = db.transaction(obj_store);
-      var store = tx.objectStore(obj_store);
-      var get_request = store.get(module_key);
-      get_request.onsuccess = function() {
-        var mod = get_request.result;
-        db.close();
-        assert_true(mod instanceof WebAssembly.Module);
-        try {
-          var instance = new WebAssembly.Instance(mod);
-          resolve(instance.exports.increment(1));
-        } catch(e) {
-          reject(e);
-        }
-      };
-      get_request.onerror = reject;
-    };
-  });
-}
-
-function TestIndexedDBLoadStoreSecure() {
-  return createAndSaveToIndexedDB(db_name)
-    .then(() => loadFromIndexedDB(db_name))
-    .then(res => assert_equals(res, 2),
-          error => assert_unreached(error));
-}
-
-function TestIndexedDBLoadStoreInsecure() {
-  return createAndSaveToIndexedDB(db_name)
-    .then(assert_unreached,
-          error => {
-            assert_true(error instanceof DOMException);
-            assert_equals(error.name, 'DataCloneError');
-          });
-}
-
-function SaveToIDBAndLoadInWorker() {
-  return createAndSaveToIndexedDB(db_name)
-  .then(() => {
-    var worker = new Worker("wasm_idb_worker.js");
-    return new Promise((resolve, reject) => {
-      worker.onmessage = function (event) {
-        if (typeof (event.data) == "string") {
-          resolve(event.data);
-          worker.terminate();
-          worker = undefined;
-        }
-      };
-      worker.postMessage({command: "load", db_name: db_name});
-    })
-  })
-.then(data => assert_equals(data, "ok"),
-    error => assert_unreached(error));
-}
-
-function SaveToIDBInWorkerAndLoadInMain() {
-  var worker = new Worker("wasm_idb_worker.js");
-  var ret = new Promise((resolve, reject) => {
-    worker.onmessage = function (event) {
-      if (typeof (event.data) == "string") {
-        resolve(event.data);
-        worker.terminate();
-        worker = undefined;
-      }
-    };
-  })
-  worker.postMessage({command: "save", db_name: db_name});
-  return ret
-    .then(data => assert_equals(data, "ok"),
-          error => assert_unreached(error))
-    .then(() => loadFromIndexedDB(db_name))
-    .then(res => assert_equals(res, 2),
-          assert_unreached);
-}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceTransport-extension.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceTransport-extension.https.html
new file mode 100644
index 0000000..1f7273f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceTransport-extension.https.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCIceTransport-extensions.https.html</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+// These tests are based on the following extension specification:
+// https://w3c.github.io/webrtc-ice/
+
+test(() => {
+  const iceTransport = new RTCIceTransport();
+}, 'RTCIceTransport constructor does not throw.');
+
+test(() => {
+  const iceTransport = new RTCIceTransport();
+  assert_equals(iceTransport.role, null, 'Expect role to be null');
+  assert_equals(iceTransport.state, 'new', `Expect state to be 'new'`);
+  assert_equals(iceTransport.gatheringState, 'new',
+    `Expect gatheringState to be 'new'`);
+  assert_array_equals(iceTransport.getLocalCandidates(), [],
+    'Expect no local candidates');
+  assert_array_equals(iceTransport.getRemoteCandidates(), [],
+    'Expect no remote candidates');
+  assert_equals(iceTransport.getSelectedCandidatePair(), null,
+    'Expect no selected candidate pair');
+  assert_equals(iceTransport.getLocalParameters(), null,
+    'Expect no local parameters');
+  assert_equals(iceTransport.getRemoteParameters(), null,
+    'Expect no remote parameters');
+}, 'RTCIceTransport initial properties are set.');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-constructor-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-constructor-expected.txt
index 6e5a466..a20bbe5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-constructor-expected.txt
@@ -13,10 +13,10 @@
 PASS new RTCPeerConnection({ certificates: [null] })
 PASS new RTCPeerConnection({ certificates: [undefined] })
 PASS new RTCPeerConnection({ iceCandidatePoolSize: toNumberThrows })
-FAIL localDescription initial value assert_equals: expected null but got object "[object RTCSessionDescription]"
+PASS localDescription initial value
 FAIL currentLocalDescription initial value assert_equals: expected (object) null but got (undefined) undefined
 FAIL pendingLocalDescription initial value assert_equals: expected (object) null but got (undefined) undefined
-FAIL remoteDescription initial value assert_equals: expected null but got object "[object RTCSessionDescription]"
+PASS remoteDescription initial value
 FAIL currentRemoteDescription initial value assert_equals: expected (object) null but got (undefined) undefined
 FAIL pendingRemoteDescription initial value assert_equals: expected (object) null but got (undefined) undefined
 PASS signalingState initial value
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/idlharness.https.window-expected.txt
index 5c5f591..380e5aa3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -321,24 +321,24 @@
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onstatechange" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onerror" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL RTCIceTransport interface: existence and properties of interface object assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface object length assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface object name assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute role assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute component assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute state assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute gatheringState assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getLocalCandidates() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getRemoteCandidates() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getSelectedCandidatePair() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getLocalParameters() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getRemoteParameters() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute onstatechange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
+FAIL RTCIceTransport interface: existence and properties of interface object assert_equals: prototype of RTCIceTransport is not EventTarget expected function "function EventTarget() { [native code] }" but got function "function () { [native code] }"
+PASS RTCIceTransport interface object length
+PASS RTCIceTransport interface object name
+FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_equals: prototype of RTCIceTransport.prototype is not EventTarget.prototype expected object "[object EventTarget]" but got object "[object Object]"
+PASS RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property
+PASS RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property
+PASS RTCIceTransport interface: attribute role
+FAIL RTCIceTransport interface: attribute component assert_true: The prototype object must have a property "component" expected true got false
+PASS RTCIceTransport interface: attribute state
+PASS RTCIceTransport interface: attribute gatheringState
+PASS RTCIceTransport interface: operation getLocalCandidates()
+PASS RTCIceTransport interface: operation getRemoteCandidates()
+PASS RTCIceTransport interface: operation getSelectedCandidatePair()
+PASS RTCIceTransport interface: operation getLocalParameters()
+PASS RTCIceTransport interface: operation getRemoteParameters()
+FAIL RTCIceTransport interface: attribute onstatechange assert_true: The prototype object must have a property "onstatechange" expected true got false
+FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_true: The prototype object must have a property "ongatheringstatechange" expected true got false
+FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
 FAIL RTCIceTransport must be primary interface of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL Stringification of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "role" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer-expected.txt
new file mode 100644
index 0000000..033d418
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+FAIL Same-origin top-level module script loading with "no-referrer" referrer policy assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/new-worker-window.html"
+FAIL Same-origin top-level module script loading with "origin" referrer policy assert_equals: expected "http://web-platform.test:8001/" but got "http://web-platform.test:8001/workers/modules/resources/new-worker-window.html"
+PASS Same-origin top-level module script loading with "same-origin" referrer policy
+FAIL Same-origin static import with "no-referrer" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js"
+FAIL Same-origin static import with "origin" referrer policy. assert_equals: expected "http://web-platform.test:8001/" but got "http://web-platform.test:8001/workers/modules/resources/static-import-same-origin-referrer-checker-worker.js"
+PASS Same-origin static import with "same-origin" referrer policy.
+FAIL Cross-origin static import with "no-referrer" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js"
+FAIL Cross-origin static import with "origin" referrer policy. assert_equals: expected "http://web-platform.test:8001/" but got "http://web-platform.test:8001/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js"
+FAIL Cross-origin static import with "same-origin" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js"
+FAIL Same-origin dynamic import with "no-referrer" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js"
+FAIL Same-origin dynamic import with "origin" referrer policy. assert_equals: expected "http://web-platform.test:8001/" but got "http://web-platform.test:8001/workers/modules/resources/dynamic-import-same-origin-referrer-checker-worker.js"
+PASS Same-origin dynamic import with "same-origin" referrer policy.
+FAIL Cross-origin dynamic import with "no-referrer" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js"
+FAIL Cross-origin dynamic import with "origin" referrer policy. assert_equals: expected "http://web-platform.test:8001/" but got "http://web-platform.test:8001/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js"
+FAIL Cross-origin dynamic import with "same-origin" referrer policy. assert_equals: expected "" but got "http://web-platform.test:8001/workers/modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer.html b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer.html
index e84b0ad..e13c0e2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-referrer.html
@@ -12,11 +12,6 @@
   return win;
 }
 
-// Returns a URL string from the current path and the given relative path.
-function createURLString(relative_path) {
-  return (new URL(relative_path, location.href)).href;
-}
-
 // Removes URL parameters from the given URL string and returns it.
 function removeParams(url_string) {
   if (!url_string)
@@ -27,6 +22,23 @@
   return url.href;
 }
 
+// Generates a referrer given a fetchType, referrer policy, and a request URL
+// (used to determine whether request is remote-origin or not). This function
+// is used to generate expected referrers.
+function generateExpectedReferrer(referrerURL, referrerPolicy, requestURL) {
+  let generatedReferrer = "";
+  if (referrerPolicy === 'no-referrer')
+    generatedReferrer = "";
+  else if (referrerPolicy === 'origin')
+    generatedReferrer = new URL('resources/' + referrerURL, location.href).origin + '/';
+  else if (referrerPolicy === 'same-origin')
+    generatedReferrer = requestURL.includes('remote') ? "" : new URL('resources/' + referrerURL, location.href).href;
+  else
+    generatedReferrer = new URL('resources/' + referrerURL, location.href).href;
+
+  return generatedReferrer;
+}
+
 // Runs a referrer policy test with the given settings. This opens a new window
 // that starts a dedicated worker.
 //
@@ -36,16 +48,16 @@
 //     scriptURL: 'resources/referrer-checker.sub.js',
 //     windowReferrerPolicy: 'no-referrer',
 //     workerReferrerPolicy: 'same-origin',
-//     moduleGraphLevel: 'top-level' (or 'descendant')
+//     fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
 //   };
 //
 // - |scriptURL| is used for starting a new worker.
-// - |windowReferrerPolicy| is set to the ReferrerPolicy HTTP header of the
+// - |windowReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
 //   window. This policy should be applied to top-level worker module script
 //   loading and static imports.
-// - |workerReferrerPolicy| is set to the ReferrerPolicy HTTP header of the
+// - |workerReferrerPolicy| is to set the ReferrerPolicy HTTP header of the
 //   worker. This policy should be applied to dynamic imports.
-// - |moduleGraphLevel| indicates a script whose referrer will be tested.
+// - |fetchType| indicates a script whose referrer will be tested.
 function import_referrer_test(settings, description) {
   promise_test(async () => {
     let windowURL = 'resources/new-worker-window.html';
@@ -68,11 +80,30 @@
     win.postMessage(scriptURL, '*');
     const msgEvent = await new Promise(resolve => window.onmessage = resolve);
 
+    // Generate the expected referrer, given:
+    //   - The fetchType of the test
+    //   - Referrer URL to be used
+    //   - Relevant referrer policy
+    //   - Request URL
     let expectedReferrer;
-    if (settings.moduleGraphLevel == 'top-level')
-      expectedReferrer = createURLString('resources/new-worker-window.html');
-    else
-      expectedReferrer = createURLString('resources/' + settings.scriptURL);
+    if (settings.fetchType === 'top-level') {
+      // Top-level worker requests have their outgoing referrers set given their
+      // containing window's URL and referrer policy.
+      expectedReferrer = generateExpectedReferrer('new-worker-window.html', settings.windowReferrerPolicy, settings.scriptURL);
+    } else if (settings.fetchType === 'descendant-static') {
+      // Static descendant script requests from a worker have their outgoing
+      // referrer set given their containing script's URL and containing
+      // window's referrer policy.
+
+      // In the below cases, the referrer URL and the request URLs are the same
+      // because the initial request (for the top-level worker script) should
+      // act as the referrer for future descendant requests.
+      expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.windowReferrerPolicy, settings.scriptURL);
+    } else if (settings.fetchType === 'descendant-dynamic') {
+      // Dynamic descendant script requests from a worker have their outgoing
+      // referrer set given their containing script's URL and referrer policy.
+      expectedReferrer = generateExpectedReferrer(settings.scriptURL, settings.workerReferrerPolicy, settings.scriptURL);
+    }
 
     // Delete query parameters from the actual referrer to make it easy to match
     // it with the expected referrer.
@@ -84,128 +115,129 @@
 
 // Tests for top-level worker module script loading.
 //
-// Top-level worker module script loading should obey the default referrer
-// policy (not the window's referrer policy), and send the window's URL as a
-// referrer.
+// Top-level worker module scripts should inherit the containing window's
+// referrer policy when using the containing window's URL as the referrer.
 //
 // [Current document]
 // --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
-//   --(new Worker)--> [Worker] should be loaded with [Window]'s URL as a
-//                     referrer regardless of |windowReferrerPolicy|.
+//   --(new Worker)--> [Worker] should respect [windowReferrerPolicy| when
+//                     using [Window]'s URL as the referrer.
 
 import_referrer_test(
     { scriptURL: 'referrer-checker.py',
       windowReferrerPolicy: 'no-referrer',
-      moduleGraphLevel: 'top-level' },
+      fetchType: 'top-level' },
     'Same-origin top-level module script loading with "no-referrer" referrer ' +
         'policy');
 
 import_referrer_test(
     { scriptURL: 'referrer-checker.py',
       windowReferrerPolicy: 'origin',
-      moduleGraphLevel: 'top-level' },
+      fetchType: 'top-level' },
     'Same-origin top-level module script loading with "origin" referrer ' +
         'policy');
 
 import_referrer_test(
     { scriptURL: 'referrer-checker.py',
       windowReferrerPolicy: 'same-origin',
-      moduleGraphLevel: 'top-level' },
+      fetchType: 'top-level' },
     'Same-origin top-level module script loading with "same-origin" referrer ' +
         'policy');
 
 // Tests for static imports.
 //
-// Static imports should obey the default referrer policy, and send the worker's
-// URL as a referrer.
+// Static imports should inherit the containing window's referrer policy when
+// using the containing module script's URL as the referrer.
+// Note: This is subject to change in the future; see
+// https://github.com/w3c/webappsec-referrer-policy/issues/111.
 //
 // [Current document]
 // --(open)--> [Window] whose referrer policy is |windowReferrerPolicy|.
 //   --(new Worker)--> [Worker]
-//     --(static import)--> [Script] should be loaded with [Worker]'s URL as a
-//                          referrer regardless of |windowReferrerPolicy|.
+//     --(static import)--> [Script] should respect |windowReferrerPolicy| when
+//                          using [Worker]'s URL as the referrer.
 
 import_referrer_test(
     { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
       windowReferrerPolicy: 'no-referrer',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Same-origin static import with "no-referrer" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
       windowReferrerPolicy: 'origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Same-origin static import with "origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'static-import-same-origin-referrer-checker-worker.js',
       windowReferrerPolicy: 'same-origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Same-origin static import with "same-origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
       windowReferrerPolicy: 'no-referrer',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Cross-origin static import with "no-referrer" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
       windowReferrerPolicy: 'origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Cross-origin static import with "origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'static-import-remote-origin-referrer-checker-worker.sub.js',
       windowReferrerPolicy: 'same-origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-static' },
     'Cross-origin static import with "same-origin" referrer policy.');
 
 // Tests for dynamic imports.
 //
-// Dynamic imports should obey the default referrer policy (not the worker's
-// referrer policy), and send the worker's URL as a referrer.
+// Dynamic imports should inherit the containing script's referrer policy if
+// set, and use the default referrer policy otherwise, when using the
+// containing script's URL as the referrer.
 //
 // [Current document]
 // --(open)--> [Window]
 //   --(new Worker)--> [Worker] whose referrer policy is |workerReferrerPolicy|.
-//     --(dynamic import)--> [Script] should be loaded with [Worker]'s URL as a
-//                           referrer regardless of |workerReferrerPolicy|.
+//     --(dynamic import)--> [Script] should respect |workerReferrerPolicy| when
+//                           using [Worker]'s URL as the referrer.
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
       workerReferrerPolicy: 'no-referrer',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Same-origin dynamic import with "no-referrer" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
       workerReferrerPolicy: 'origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Same-origin dynamic import with "origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-same-origin-referrer-checker-worker.js',
       workerReferrerPolicy: 'same-origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Same-origin dynamic import with "same-origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
       workerReferrerPolicy: 'no-referrer',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Cross-origin dynamic import with "no-referrer" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
       workerReferrerPolicy: 'origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Cross-origin dynamic import with "origin" referrer policy.');
 
 import_referrer_test(
     { scriptURL: 'dynamic-import-remote-origin-referrer-checker-worker.sub.js',
       workerReferrerPolicy: 'same-origin',
-      moduleGraphLevel: 'descendant' },
+      fetchType: 'descendant-dynamic' },
     'Cross-origin dynamic import with "same-origin" referrer policy.');
-
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt
new file mode 100644
index 0000000..ba0d50f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/animation-worklet-referrer.https-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+FAIL Importing a same-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a page that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt
new file mode 100644
index 0000000..ba0d50f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/layout-worklet-referrer.https-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+FAIL Importing a same-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a page that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt
new file mode 100644
index 0000000..ba0d50f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/paint-worklet-referrer.https-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+FAIL Importing a same-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a page that has "origin" referrer policy should send only an origin as referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a page that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a page that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "no-referrer" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a same-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a same-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "origin" referrer policy should send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+PASS Importing a same-origin script from a same-origin worklet script that has "same-origin" referrer policy should send referrer.
+FAIL Importing a remote-origin script from a same-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+FAIL Importing a remote-origin script from a remote-origin worklet script that has "same-origin" referrer policy should not send referrer. assert_equals: expected "RESOLVED" but got "The user aborted a request."
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-checker.py b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-checker.py
index 3d9afb4..8f37983 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-checker.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-checker.py
@@ -1,15 +1,24 @@
 # Returns a valid response when request's |referrer| matches
 # |expected_referrer|.
 def main(request, response):
-    referrer = request.headers.get("referer", "")
+    # We want |referrer| to be the referrer header with no query params,
+    # because |expected_referrer| will not contain any query params, and
+    # thus cannot be compared with the actual referrer header if it were to
+    # contain query params. This works fine if the actual referrer has no
+    # query params too.
+    referrer = request.headers.get("referer", "").split("?")[0]
+    referrer_policy = request.GET.first("referrer_policy")
     expected_referrer = request.GET.first("expected_referrer", "")
-
     response_headers = [("Content-Type", "text/javascript"),
                         ("Access-Control-Allow-Origin", "*")]
 
-    # The expected referrer doesn't contain query params for simplification, so
-    # we check the referrer by startswith() here.
-    if (expected_referrer != "" and
-        referrer.startswith(expected_referrer + "?")):
-        return (200, response_headers, "")
+    if referrer_policy == "no-referrer" or referrer_policy == "origin":
+        if referrer == expected_referrer:
+            return (200, response_headers, "")
+        return (404, response_headers)
+
+    if referrer_policy == "same-origin":
+        if referrer == expected_referrer:
+            return (200, response_headers, "")
+        return (404, response_headers)
     return (404, response_headers)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
index e46f93db..01b8e2a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-tests.js
@@ -29,9 +29,7 @@
   }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
 }
 
-// Runs a series of tests related to the referrer policy on a worklet. Referrer
-// on worklet module loading should always be handled with the default referrer
-// policy.
+// Runs a series of tests related to the referrer policy on a worklet.
 //
 // Usage:
 // runReferrerTests("paint");
@@ -46,7 +44,7 @@
                              referrerPolicy: 'no-referrer',
                              scriptOrigins: { topLevel: 'same' } });
   }, 'Importing a same-origin script from a page that has "no-referrer" ' +
-     'referrer policy.');
+     'referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -54,7 +52,7 @@
                              referrerPolicy: 'no-referrer',
                              scriptOrigins: { topLevel: 'remote' } });
   }, 'Importing a remote-origin script from a page that has "no-referrer" ' +
-     'referrer policy.');
+     'referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -62,7 +60,7 @@
                              referrerPolicy: 'origin',
                              scriptOrigins: { topLevel: 'same' } });
   }, 'Importing a same-origin script from a page that has "origin" ' +
-     'referrer policy.');
+     'referrer policy should send only an origin as referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -70,7 +68,7 @@
                              referrerPolicy: 'origin',
                              scriptOrigins: { topLevel: 'remote' } });
   }, 'Importing a remote-origin script from a page that has "origin" ' +
-     'referrer policy.');
+     'referrer policy should send only an origin as referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -78,7 +76,7 @@
                              referrerPolicy: 'same-origin',
                              scriptOrigins: { topLevel: 'same' } });
   }, 'Importing a same-origin script from a page that has "same-origin" ' +
-     'referrer policy.');
+     'referrer policy should send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -86,7 +84,7 @@
                              referrerPolicy: 'same-origin',
                              scriptOrigins: { topLevel: 'remote' } });
   }, 'Importing a remote-origin script from a page that has "same-origin" ' +
-     'referrer policy.');
+     'referrer policy should not send referrer.');
 
   // Tests for descendant script fetch -----------------------------------------
 
@@ -97,7 +95,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'same' } });
   }, 'Importing a same-origin script from a same-origin worklet script that ' +
-     'has "no-referrer" referrer policy.');
+     'has "no-referrer" referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -106,7 +104,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a same-origin worklet script ' +
-     'that has "no-referrer" referrer policy.');
+     'that has "no-referrer" referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -115,7 +113,7 @@
                              scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
-     'that has "no-referrer" referrer policy.');
+     'that has "no-referrer" referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -124,7 +122,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'same' } });
   }, 'Importing a same-origin script from a same-origin worklet script that ' +
-     'has "origin" referrer policy.');
+     'has "origin" referrer policy should send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -133,7 +131,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a same-origin worklet script ' +
-     'that has "origin" referrer policy.');
+     'that has "origin" referrer policy should send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -142,7 +140,7 @@
                              scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
-     'that has "origin" referrer policy.');
+     'that has "origin" referrer policy should send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -151,7 +149,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'same' } });
   }, 'Importing a same-origin script from a same-origin worklet script that ' +
-     'has "same-origin" referrer policy.');
+     'has "same-origin" referrer policy should send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -160,7 +158,7 @@
                              scriptOrigins: { topLevel: 'same',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a same-origin worklet script ' +
-     'that has "same-origin" referrer policy.');
+     'that has "same-origin" referrer policy should not send referrer.');
 
   promise_test(() => {
     return runReferrerTest({ workletType: workletType,
@@ -169,5 +167,5 @@
                              scriptOrigins: { topLevel: 'remote',
                                               descendant: 'remote' } });
   }, 'Importing a remote-origin script from a remote-origin worklet script ' +
-     'that has "same-origin" referrer policy.');
+     'that has "same-origin" referrer policy should not send referrer.');
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
index 331db0793..4817f045 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/referrer-window.html
@@ -48,30 +48,47 @@
   assert_unreached('fetchType has an invalid value.');
 }
 
+function createExpectedReferrer(
+    importerURL, fetchType, referrerPolicy, scriptOrigins) {
+  if (referrerPolicy === 'no-referrer')
+    return "";
+  if (referrerPolicy === 'same-origin') {
+    if (isDestinationCrossOrigin(fetchType, scriptOrigins))
+      return "";
+    // Delete query params to make it easier to match with an actual referrer in
+    // the referrer-checker.py.
+    const expectedReferrer = new URL(importerURL);
+    for (var key of expectedReferrer.searchParams.keys())
+      expectedReferrer.searchParams.delete(key);
+    return expectedReferrer;
+  }
+  if (referrerPolicy === 'origin')
+    return (new URL(importerURL)).origin + '/';
+  assert_unreached('referrerPolicy has an invalid value.');
+}
+
 window.onmessage = e => {
   const workletType = e.data.workletType;
   const fetchType = e.data.fetchType;
+  const referrerPolicy = e.data.referrerPolicy;
   const scriptOrigins = e.data.scriptOrigins;
 
   let scriptURL;
   let expectedReferrer;
   if (fetchType === 'top-level') {
     scriptURL = createScriptURLForTopLevel(scriptOrigins.topLevel);
-    // The referrer of the top-level script should be this file.
-    // Delete query params to make it easier to match with an actual referrer in
-    // the referrer-checker.py.
-    expectedReferrer = new URL(location.href);
-    for (var key of expectedReferrer.searchParams.keys())
-      expectedReferrer.searchParams.delete(key);
+    expectedReferrer = createExpectedReferrer(
+        location.href, fetchType, referrerPolicy, scriptOrigins);
   } else if (fetchType === 'descendant') {
     scriptURL = createScriptURLForDecendant(scriptOrigins);
-    // The referrer of the imported script should be the importer script.
-    expectedReferrer = scriptURL;
+    expectedReferrer = createExpectedReferrer(
+        scriptURL, fetchType, referrerPolicy, scriptOrigins);
   } else {
     assert_unreached('fetchType should be \'top-level\' or \'descendant\'');
   }
 
   const params = new URLSearchParams;
+  params.append('referrer_policy', referrerPolicy);
   params.append('expected_referrer', expectedReferrer);
 
   get_worklet(workletType).addModule(scriptURL + '?' + params)
diff --git a/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html b/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html
index c0d358148..30e177e 100644
--- a/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html
+++ b/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html
@@ -9,26 +9,6 @@
 const redStyleTexts = [".red { color: red; }", ".red + span + span { color: red; }"];
 
 test(() => {
-  const sheet = new CSSStyleSheet({title: "Red", disabled: true, media: "screen, print"});
-  assert_equals(sheet.title, "Red");
-  assert_equals(sheet.ownerNode, null);
-  assert_equals(sheet.ownerRule, null);
-  assert_equals(sheet.media.length, 2);
-  assert_equals(sheet.media.item(0), "screen");
-  assert_equals(sheet.media.item(1), "print");
-  assert_true(sheet.disabled);
-  assert_equals(sheet.cssRules.length, 0);
-
-  sheet.insertRule(redStyleTexts[0]);
-  assert_equals(sheet.cssRules.length, 1);
-  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
-
-  sheet.insertRule(redStyleTexts[1]);
-  assert_equals(sheet.cssRules.length, 2);
-  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
-}, 'Empty CSSStyleSheet can be constructed using script');
-
-test(() => {
   const sheet = document.createEmptyCSSStyleSheet({title: "Red", disabled: true, media: "screen, print"});
   assert_equals(sheet.title, "Red");
   assert_equals(sheet.ownerNode, null);
diff --git a/third_party/WebKit/LayoutTests/fast/dom/dom-constructors-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/dom-constructors-expected.txt
index 39d0f34..ee72f095 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/dom-constructors-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/dom-constructors-expected.txt
@@ -74,7 +74,7 @@
 PASS TryAllocate('CSSRuleList') is 'exception'
 PASS TryAllocate('CSSStyleDeclaration') is 'exception'
 PASS TryAllocate('CSSStyleRule') is 'exception'
-FAIL TryAllocate('CSSStyleSheet') should be exception. Was [object CSSStyleSheet].
+PASS TryAllocate('CSSStyleSheet') is 'exception'
 PASS TryAllocate('DOMImplementation') is 'exception'
 PASS TryAllocate('HTMLCollection') is 'exception'
 PASS TryAllocate('MediaList') is 'exception'
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/soft-context-menu.js b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/soft-context-menu.js
index 311ae06..6552c13 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/soft-context-menu.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/soft-context-menu.js
@@ -76,13 +76,14 @@
     do {
       if (selection)
         selection += ' -> ';
-      if (subMenu._contextMenuElement === activeElement)
+      const focused = (subMenu._highlightedMenuItemElement || subMenu._contextMenuElement) === activeElement;
+      if (focused)
         selection += '[';
       if (subMenu._highlightedMenuItemElement)
         selection += subMenu._highlightedMenuItemElement.textContent.replace(/[^A-z0-9 ]/g, '');
       else
         selection += 'null'
-      if (subMenu._contextMenuElement === activeElement)
+      if (focused)
         selection += ']';
     }
     while (subMenu = subMenu._subMenu)
diff --git a/third_party/WebKit/LayoutTests/media/controls/offline-play-button-expected.html b/third_party/WebKit/LayoutTests/media/controls/offline-play-button-expected.html
new file mode 100644
index 0000000..4aa0458
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/controls/offline-play-button-expected.html
@@ -0,0 +1 @@
+<video controls>
diff --git a/third_party/WebKit/LayoutTests/media/controls/offline-play-button.mht b/third_party/WebKit/LayoutTests/media/controls/offline-play-button.mht
new file mode 100644
index 0000000..f2a1bddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/controls/offline-play-button.mht
@@ -0,0 +1,19 @@
+From: <Saved by Blink>

+Snapshot-Content-Location: data:text/html,<video controls>

+Subject: 

+Date: Wed, 8 Aug 2018 03:40:01 -0000

+MIME-Version: 1.0

+Content-Type: multipart/related;

+	type="text/html";

+	boundary="----MultipartBoundary--vMHcSo6MOQ8bNqjzscEyfel3Kzz93I3pZg8BXOlrNK----"

+

+

+------MultipartBoundary--vMHcSo6MOQ8bNqjzscEyfel3Kzz93I3pZg8BXOlrNK----

+Content-Type: text/html

+Content-ID: <frame-EABF2B3BFD6D225D86B7362F1A016751@mhtml.blink>

+Content-Transfer-Encoding: quoted-printable

+Content-Location: data:text/html,<video controls>

+

+<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; charset=

+=3Dwindows-1252"></head><body><video controls=3D""></video></body></html>

+------MultipartBoundary--vMHcSo6MOQ8bNqjzscEyfel3Kzz93I3pZg8BXOlrNK------

diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-absolute-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-absolute-layer-with-reflection-expected.txt
index 7bbf22f1..c3830b6 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-absolute-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-absolute-layer-with-reflection-expected.txt
@@ -45,10 +45,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='absolute clipped'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow (relative positioned) DIV class='relative reflected'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-fixed-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-fixed-layer-with-reflection-expected.txt
index c3d8353..8f28c78 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-fixed-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/reflection/scroll-fixed-layer-with-reflection-expected.txt
@@ -45,10 +45,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green reflected'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.png
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/fixed-img-src-change-after-scroll-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/fixed-img-src-change-after-scroll-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/fixed-img-src-change-after-scroll-expected.png
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/fixed-img-src-change-after-scroll-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt
index 85d9057..f5ed717 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt
@@ -1,9 +1,4 @@
 {
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "full"
-    }
-  ]
+
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt
index b0a29f0..13b1cfa 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "full"
-    },
-    {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt
index c971603..662ba22 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV class='innerWrapper'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow DIV class='red'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
index 33e32fc..a688cc26 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
@@ -25,22 +25,11 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow DIV id='scroller'",
-          "rect": [0, 0, 302, 302],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='scroller'",
           "rect": [1, 201, 100, 100],
           "reason": "chunk appeared"
         }
       ]
     }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='scroller'",
-      "reason": "full"
-    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
index 88e6b62..922711a 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
@@ -24,23 +24,12 @@
       "backfaceVisibility": "hidden",
       "paintInvalidations": [
         {
-          "object": "LayoutBlockFlow DIV id='scroller'",
-          "rect": [0, 0, 302, 302],
-          "reason": "full"
-        },
-        {
           "object": "LayoutBlockFlow DIV id='target'",
           "rect": [1, 201, 100, 100],
           "reason": "chunk appeared"
         }
       ]
     }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='scroller'",
-      "reason": "full"
-    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt
index 615ed6c9..5d81d66 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt
@@ -18,11 +18,6 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutBlockFlow DIV class='scroller'",
-          "rect": [18, 60, 310, 200],
-          "reason": "full"
-        },
-        {
           "object": "LayoutBlockFlow (positioned) DIV class='back'",
           "rect": [93, 125, 180, 100],
           "reason": "paint property change"
@@ -77,10 +72,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV class='scroller'",
-      "reason": "full"
-    },
-    {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
index b0a29f0..13b1cfa 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "full"
-    },
-    {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.png
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
index 958284e..06fd400 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
@@ -45,10 +45,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt
index 511b1aa..d39a9c0 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='absolute clipped'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow (relative positioned) DIV class='relative green'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt
index 63c5448..bbaa509 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt
@@ -45,10 +45,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
-      "reason": "full"
-    },
-    {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt
index 7dc14b5..009a0e4f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt
@@ -33,7 +33,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='absolute clipped rotated'",
-      "reason": "full"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.png
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
rename to third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt
index 2b950e5f..3cef082d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt
@@ -29,12 +29,6 @@
         }
       ]
     }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow (positioned) DIV id='moveMe' class='absolute clipped'",
-      "reason": "full"
-    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-inside-table-cell-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-inside-table-cell-expected.txt
index 5727385..2a60c32 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-inside-table-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-inside-table-cell-expected.txt
@@ -18,11 +18,6 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [312, 112, 454, 469],
-          "reason": "full"
-        },
-        {
           "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
           "rect": [314, 114, 435, 450],
           "reason": "paint property change"
@@ -37,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-      "reason": "full"
-    },
-    {
       "object": "HorizontalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-relative-table-inside-table-cell-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-relative-table-inside-table-cell-expected.txt
index 179f292..e4529f2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-relative-table-inside-table-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/scroll-relative-table-inside-table-cell-expected.txt
@@ -18,11 +18,6 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [1112, 1312, 454, 469],
-          "reason": "full"
-        },
-        {
           "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
           "rect": [1114, 1314, 435, 450],
           "reason": "paint property change"
@@ -50,10 +45,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-      "reason": "full"
-    },
-    {
       "object": "HorizontalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-auto-in-overflow-auto-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-auto-in-overflow-auto-scrolled-expected.txt
index 10b246a..9675bc2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-auto-in-overflow-auto-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-auto-in-overflow-auto-scrolled-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "full"
-    },
-    {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt
index 10b246a..9675bc2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt
@@ -32,10 +32,6 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "full"
-    },
-    {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
     }
diff --git a/third_party/WebKit/LayoutTests/paint/masks/mask-change-crash.html b/third_party/WebKit/LayoutTests/paint/masks/mask-change-crash.html
new file mode 100644
index 0000000..746ffcff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/masks/mask-change-crash.html
@@ -0,0 +1,13 @@
+<!doctype HTML>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+  runAfterLayoutAndPaint(t.step_func_done(() => {
+    target.style.webkitMaskImage = 'url(#foo)';
+  }));
+});
+</script>
+Passes if it does not crash.
+<textarea style="transform: translateX(1px)" id="target"></textarea>
diff --git a/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/historical-expected.txt b/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/historical-expected.txt
deleted file mode 100644
index bf2c547..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/historical-expected.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-This is a testharness.js-based test.
-Found 72 tests; 68 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS Historical DOM features must be removed: DOMConfiguration
-FAIL Historical DOM features must be removed: DOMError assert_equals: expected (undefined) undefined but got (function) function "function DOMError() { [native code] }"
-PASS Historical DOM features must be removed: DOMErrorHandler
-PASS Historical DOM features must be removed: DOMImplementationList
-PASS Historical DOM features must be removed: DOMImplementationSource
-PASS Historical DOM features must be removed: DOMLocator
-PASS Historical DOM features must be removed: DOMObject
-PASS Historical DOM features must be removed: DOMSettableTokenList
-PASS Historical DOM features must be removed: DOMUserData
-PASS Historical DOM features must be removed: Entity
-PASS Historical DOM features must be removed: EntityReference
-PASS Historical DOM features must be removed: EventException
-PASS Historical DOM features must be removed: NameList
-PASS Historical DOM features must be removed: Notation
-PASS Historical DOM features must be removed: TypeInfo
-PASS Historical DOM features must be removed: UserDataHandler
-PASS Historical DOM features must be removed: RangeException
-PASS Historical DOM features must be removed: createEntityReference
-FAIL Historical DOM features must be removed: xmlEncoding assert_equals: expected (undefined) undefined but got (object) null
-FAIL Historical DOM features must be removed: xmlStandalone assert_equals: expected (undefined) undefined but got (boolean) false
-FAIL Historical DOM features must be removed: xmlVersion assert_equals: expected (undefined) undefined but got (object) null
-PASS Historical DOM features must be removed: strictErrorChecking
-PASS Historical DOM features must be removed: domConfig
-PASS Historical DOM features must be removed: normalizeDocument
-PASS Historical DOM features must be removed: renameNode
-PASS Historical DOM features must be removed: defaultCharset
-PASS Historical DOM features must be removed: height
-PASS Historical DOM features must be removed: width
-PASS Historical DOM features must be removed: commands
-PASS Historical DOM features must be removed: cssElementMap
-PASS Historical DOM features must be removed: async
-PASS document.load
-PASS DOMImplementation.getFeature() must be nuked.
-PASS Historical DOM features must be removed: schemaTypeInfo
-PASS Historical DOM features must be removed: setIdAttribute
-PASS Historical DOM features must be removed: setIdAttributeNS
-PASS Historical DOM features must be removed: setIdAttributeNode
-PASS Attr member must be nuked: schemaTypeInfo
-PASS Attr member must be nuked: isId
-PASS DocumentType member must be nuked: entities
-PASS DocumentType member must be nuked: notations
-PASS DocumentType member must be nuked: internalSubset
-PASS Text member must be nuked: isElementContentWhitespace
-PASS Text member must be nuked: replaceWholeText
-PASS Node member must be nuked: hasAttributes
-PASS Node member must be nuked: attributes
-PASS Node member must be nuked: namespaceURI
-PASS Node member must be nuked: prefix
-PASS Node member must be nuked: localName
-PASS Node member must be nuked: isSupported
-PASS Node member must be nuked: getFeature
-PASS Node member must be nuked: getUserData
-PASS Node member must be nuked: setUserData
-PASS Node member must be nuked: rootNode
-PASS Window member must be nuked: attachEvent
-PASS Event should not have this constant: MOUSEDOWN
-PASS Event should not have this constant: MOUSEUP
-PASS Event should not have this constant: MOUSEOVER
-PASS Event should not have this constant: MOUSEOUT
-PASS Event should not have this constant: MOUSEMOVE
-PASS Event should not have this constant: MOUSEDRAG
-PASS Event should not have this constant: CLICK
-PASS Event should not have this constant: DBLCLICK
-PASS Event should not have this constant: KEYDOWN
-PASS Event should not have this constant: KEYUP
-PASS Event should not have this constant: KEYPRESS
-PASS Event should not have this constant: DRAGDROP
-PASS Event should not have this constant: FOCUS
-PASS Event should not have this constant: BLUR
-PASS Event should not have this constant: SELECT
-PASS Event should not have this constant: CHANGE
-PASS Event.prototype should not have this property: getPreventDefault
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/idlharness.https.window-expected.txt
index 7311d7db..0dd8fb6 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -321,24 +321,24 @@
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onstatechange" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onerror" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL RTCIceTransport interface: existence and properties of interface object assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface object length assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface object name assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute role assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute component assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute state assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute gatheringState assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getLocalCandidates() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getRemoteCandidates() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getSelectedCandidatePair() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getLocalParameters() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: operation getRemoteParameters() assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute onstatechange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
-FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_own_property: self does not have own property "RTCIceTransport" expected property "RTCIceTransport" missing
+FAIL RTCIceTransport interface: existence and properties of interface object assert_equals: prototype of RTCIceTransport is not EventTarget expected function "function EventTarget() { [native code] }" but got function "function () { [native code] }"
+PASS RTCIceTransport interface object length
+PASS RTCIceTransport interface object name
+FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_equals: prototype of RTCIceTransport.prototype is not EventTarget.prototype expected object "[object EventTarget]" but got object "[object Object]"
+PASS RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property
+PASS RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property
+PASS RTCIceTransport interface: attribute role
+FAIL RTCIceTransport interface: attribute component assert_true: The prototype object must have a property "component" expected true got false
+PASS RTCIceTransport interface: attribute state
+PASS RTCIceTransport interface: attribute gatheringState
+PASS RTCIceTransport interface: operation getLocalCandidates()
+PASS RTCIceTransport interface: operation getRemoteCandidates()
+PASS RTCIceTransport interface: operation getSelectedCandidatePair()
+PASS RTCIceTransport interface: operation getLocalParameters()
+PASS RTCIceTransport interface: operation getRemoteParameters()
+FAIL RTCIceTransport interface: attribute onstatechange assert_true: The prototype object must have a property "onstatechange" expected true got false
+FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_true: The prototype object must have a property "ongatheringstatechange" expected true got false
+FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
 FAIL RTCIceTransport must be primary interface of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL Stringification of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
 FAIL RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "role" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index c763cbe0..30ed8b3 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5425,6 +5425,17 @@
     setter candidate
     setter sdpMLineIndex
     setter sdpMid
+interface RTCIceTransport
+    attribute @@toStringTag
+    getter gatheringState
+    getter role
+    getter state
+    method constructor
+    method getLocalCandidates
+    method getLocalParameters
+    method getRemoteCandidates
+    method getRemoteParameters
+    method getSelectedCandidatePair
 interface RTCPeerConnection : EventTarget
     static method generateCertificate
     attribute @@toStringTag
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index a48e31e..91d6d38 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 8f612ebb152fb7e05643a2bcf78cb89a8c0641ad
+Revision: bea85b52733022294eef108a2e42d77b616ddca2
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/WORKSPACE b/third_party/abseil-cpp/WORKSPACE
index a7b1c139..e4a91197 100644
--- a/third_party/abseil-cpp/WORKSPACE
+++ b/third_party/abseil-cpp/WORKSPACE
@@ -1,4 +1,6 @@
 workspace(name = "com_google_absl")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
 # Bazel toolchains
 http_archive(
   name = "bazel_toolchains",
@@ -13,9 +15,9 @@
 # GoogleTest/GoogleMock framework. Used by most unit-tests.
 http_archive(
      name = "com_google_googletest",
-     urls = ["https://github.com/google/googletest/archive/4e4df226fc197c0dda6e37f5c8c3845ca1e73a49.zip"],
-     strip_prefix = "googletest-4e4df226fc197c0dda6e37f5c8c3845ca1e73a49",
-     sha256 = "d4179caf54410968d1fff0b869e7d74803dd30209ee6645ccf1ca65ab6cf5e5a",
+     urls = ["https://github.com/google/googletest/archive/b4d4438df9479675a632b2f11125e57133822ece.zip"],  # 2018-07-16
+     strip_prefix = "googletest-b4d4438df9479675a632b2f11125e57133822ece",
+     sha256 = "5aaa5d566517cae711e2a3505ea9a6438be1b37fcaae0ebcb96ccba9aa56f23a",
 )
 
 # Google benchmark.
@@ -25,11 +27,3 @@
     strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
     sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
 )
-
-# RE2 regular-expression framework. Used by some unit-tests.
-http_archive(
-    name = "com_googlesource_code_re2",
-    urls = ["https://github.com/google/re2/archive/6cf8ccd82dbaab2668e9b13596c68183c9ecd13f.zip"],
-    strip_prefix = "re2-6cf8ccd82dbaab2668e9b13596c68183c9ecd13f",
-    sha256 = "279a852219dbfc504501775596089d30e9c0b29664ce4128b0ac4c841471a16a",
-)
diff --git a/third_party/abseil-cpp/absl/BUILD.bazel b/third_party/abseil-cpp/absl/BUILD.bazel
index 439addbf..edd0274c 100644
--- a/third_party/abseil-cpp/absl/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/BUILD.bazel
@@ -18,11 +18,10 @@
 
 licenses(["notice"])  # Apache 2.0
 
-config_setting(
+load(":compiler_config_setting.bzl", "create_llvm_config")
+
+create_llvm_config(
     name = "llvm_compiler",
-    values = {
-        "compiler": "llvm",
-    },
     visibility = [":__subpackages__"],
 )
 
diff --git a/third_party/abseil-cpp/absl/algorithm/container.h b/third_party/abseil-cpp/absl/algorithm/container.h
index acddec48..6af8c097 100644
--- a/third_party/abseil-cpp/absl/algorithm/container.h
+++ b/third_party/abseil-cpp/absl/algorithm/container.h
@@ -314,7 +314,7 @@
 
 // c_mismatch()
 //
-// Container-based version of the <algorithm> `std::mismatchf()` function to
+// Container-based version of the <algorithm> `std::mismatch()` function to
 // return the first element where two ordered containers differ.
 template <typename C1, typename C2>
 container_algorithm_internal::ContainerIterPairType<C1, C2>
diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel
index 35414a2..06d092e 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/base/BUILD.bazel
@@ -362,6 +362,7 @@
     copts = ABSL_TEST_COPTS,
     deps = [
         ":base",
+        "//absl/strings",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/third_party/abseil-cpp/absl/base/CMakeLists.txt b/third_party/abseil-cpp/absl/base/CMakeLists.txt
index 303533e2..01d2af08 100644
--- a/third_party/abseil-cpp/absl/base/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/base/CMakeLists.txt
@@ -310,7 +310,7 @@
 
 # test raw_logging_test
 set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc")
-set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base)
+set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base absl::strings)
 
 absl_test(
   TARGET
diff --git a/third_party/abseil-cpp/absl/base/config.h b/third_party/abseil-cpp/absl/base/config.h
index 2f5f159..6890e31 100644
--- a/third_party/abseil-cpp/absl/base/config.h
+++ b/third_party/abseil-cpp/absl/base/config.h
@@ -268,7 +268,7 @@
 #error ABSL_HAVE_MMAP cannot be directly set
 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
     defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
-    defined(__wasm__) || defined(__Fuchsia__)
+    defined(__wasm__) || defined(__Fuchsia__) || defined(__sun)
 #define ABSL_HAVE_MMAP 1
 #endif
 
diff --git a/third_party/abseil-cpp/absl/base/internal/endian_test.cc b/third_party/abseil-cpp/absl/base/internal/endian_test.cc
index f3ff4b3..e276915 100644
--- a/third_party/abseil-cpp/absl/base/internal/endian_test.cc
+++ b/third_party/abseil-cpp/absl/base/internal/endian_test.cc
@@ -33,32 +33,16 @@
 const int kNumValuesToTest = 1000000;
 const int kRandomSeed = 12345;
 
-#ifdef ABSL_IS_BIG_ENDIAN
+#if defined(ABSL_IS_BIG_ENDIAN)
 const uint64_t kInitialInNetworkOrder{kInitialNumber};
 const uint64_t k64ValueLE{0xefcdab8967452301};
 const uint32_t k32ValueLE{0x67452301};
 const uint16_t k16ValueLE{0x2301};
-const uint8_t k8ValueLE{k8Value};
-const uint64_t k64IValueLE{0xefcdab89674523a1};
-const uint32_t k32IValueLE{0x67452391};
-const uint16_t k16IValueLE{0x85ff};
-const uint8_t k8IValueLE{0xff};
-const uint64_t kDoubleValueLE{0x6e861bf0f9210940};
-const uint32_t kFloatValueLE{0xd00f4940};
-const uint8_t kBoolValueLE{0x1};
 
 const uint64_t k64ValueBE{kInitialNumber};
 const uint32_t k32ValueBE{k32Value};
 const uint16_t k16ValueBE{k16Value};
-const uint8_t k8ValueBE{k8Value};
-const uint64_t k64IValueBE{0xa123456789abcdef};
-const uint32_t k32IValueBE{0x91234567};
-const uint16_t k16IValueBE{0xff85};
-const uint8_t k8IValueBE{0xff};
-const uint64_t kDoubleValueBE{0x400921f9f01b866e};
-const uint32_t kFloatValueBE{0x40490fd0};
-const uint8_t kBoolValueBE{0x1};
-#elif defined ABSL_IS_LITTLE_ENDIAN
+#elif defined(ABSL_IS_LITTLE_ENDIAN)
 const uint64_t kInitialInNetworkOrder{0xefcdab8967452301};
 const uint64_t k64ValueLE{kInitialNumber};
 const uint32_t k32ValueLE{k32Value};
diff --git a/third_party/abseil-cpp/absl/base/internal/exception_testing.h b/third_party/abseil-cpp/absl/base/internal/exception_testing.h
index fd89a3f..0cf7918e 100644
--- a/third_party/abseil-cpp/absl/base/internal/exception_testing.h
+++ b/third_party/abseil-cpp/absl/base/internal/exception_testing.h
@@ -35,7 +35,7 @@
   EXPECT_DEATH(expr, ".*")
 #else
 #define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
-  EXPECT_DEATH(expr, text)
+  EXPECT_DEATH_IF_SUPPORTED(expr, text)
 
 #endif
 
diff --git a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
index 1ce1388..d9485a6 100644
--- a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
+++ b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
@@ -139,7 +139,7 @@
 #endif
 
 #ifdef ABSL_MIN_LOG_LEVEL
-  if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL &&
+  if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
       severity < absl::LogSeverity::kFatal) {
     enabled = false;
   }
@@ -206,6 +206,15 @@
   va_end(ap);
 }
 
+// Non-formatting version of RawLog().
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
+                               int line, const std::string& message) {
+  RawLog(severity, file, line, "%s", message.c_str());
+}
+
 bool RawLoggingFullySupported() {
 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
   return true;
@@ -214,5 +223,12 @@
 #endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
 }
 
+ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction>
+    internal_log_function(DefaultInternalLog);
+
+void RegisterInternalLogFunction(InternalLogFunction func) {
+  internal_log_function.Store(func);
+}
+
 }  // namespace raw_logging_internal
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/third_party/abseil-cpp/absl/base/internal/raw_logging.h
index a2b7207..67abfd3 100644
--- a/third_party/abseil-cpp/absl/base/internal/raw_logging.h
+++ b/third_party/abseil-cpp/absl/base/internal/raw_logging.h
@@ -19,7 +19,10 @@
 #ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
 #define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
 
+#include <string>
+
 #include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
 #include "absl/base/log_severity.h"
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
@@ -57,6 +60,34 @@
     }                                                                  \
   } while (0)
 
+// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
+// except that if the richer log library is linked into the binary, we dispatch
+// to that instead.  This is potentially useful for internal logging and
+// assertions, where we are using RAW_LOG neither for its async-signal-safety
+// nor for its non-allocating nature, but rather because raw logging has very
+// few other dependencies.
+//
+// The API is a subset of the above: each macro only takes two arguments.  Use
+// StrCat if you need to build a richer message.
+#define ABSL_INTERNAL_LOG(severity, message)                          \
+  do {                                                                \
+    constexpr const char* absl_raw_logging_internal_basename =        \
+        ::absl::raw_logging_internal::Basename(__FILE__,              \
+                                               sizeof(__FILE__) - 1); \
+    ::absl::raw_logging_internal::internal_log_function(              \
+        ABSL_RAW_LOGGING_INTERNAL_##severity,                         \
+        absl_raw_logging_internal_basename, __LINE__, message);       \
+  } while (0)
+
+#define ABSL_INTERNAL_CHECK(condition, message)               \
+  do {                                                        \
+    if (ABSL_PREDICT_FALSE(!(condition))) {                   \
+      std::string death_message = "Check " #condition " failed: "; \
+      death_message += std::string(message);                       \
+      ABSL_INTERNAL_LOG(FATAL, death_message);                \
+    }                                                         \
+  } while (0)
+
 #define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
 #define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
 #define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
@@ -131,6 +162,18 @@
 using AbortHook = void (*)(const char* file, int line, const char* buf_start,
                            const char* prefix_end, const char* buf_end);
 
+// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+using InternalLogFunction = void (*)(absl::LogSeverity severity,
+                                     const char* file, int line,
+                                     const std::string& message);
+
+extern base_internal::AtomicHook<InternalLogFunction> internal_log_function;
+
+void RegisterInternalLogFunction(InternalLogFunction func);
+
 }  // namespace raw_logging_internal
 }  // namespace absl
 
diff --git a/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
index c572436..5c7517abd 100644
--- a/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
+++ b/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
@@ -103,6 +103,47 @@
 #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
   (absl::UnalignedStore64(_p, _val))
 
+#elif defined(UNDEFINED_BEHAVIOR_SANITIZER)
+
+namespace absl {
+
+inline uint16_t UnalignedLoad16(const void *p) {
+  uint16_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32_t UnalignedLoad32(const void *p) {
+  uint32_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64_t UnalignedLoad64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
+
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
+  (absl::UnalignedStore16(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
+  (absl::UnalignedStore32(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (absl::UnalignedStore64(_p, _val))
+
 #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
     defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) ||    \
     defined(__ppc64__) || defined(__PPC64__)
diff --git a/third_party/abseil-cpp/absl/base/raw_logging_test.cc b/third_party/abseil-cpp/absl/base/raw_logging_test.cc
index dae4b351..ebbc5db90 100644
--- a/third_party/abseil-cpp/absl/base/raw_logging_test.cc
+++ b/third_party/abseil-cpp/absl/base/raw_logging_test.cc
@@ -18,12 +18,20 @@
 
 #include "absl/base/internal/raw_logging.h"
 
+#include <tuple>
+
 #include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
 
 namespace {
 
 TEST(RawLoggingCompilationTest, Log) {
   ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1);
+  ABSL_RAW_LOG(INFO, "RAW INFO: %d %d", 1, 2);
+  ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d", 1, 2, 3);
+  ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d", 1, 2, 3, 4);
+  ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d %d", 1, 2, 3, 4, 5);
+  ABSL_RAW_LOG(WARNING, "RAW WARNING: %d", 1);
   ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1);
 }
 
@@ -47,4 +55,25 @@
                             kExpectedDeathOutput);
 }
 
+TEST(InternalLog, CompilationTest) {
+  ABSL_INTERNAL_LOG(INFO, "Internal Log");
+  std::string log_msg = "Internal Log";
+  ABSL_INTERNAL_LOG(INFO, log_msg);
+
+  ABSL_INTERNAL_LOG(INFO, log_msg + " 2");
+
+  float d = 1.1f;
+  ABSL_INTERNAL_LOG(INFO, absl::StrCat("Internal log ", 3, " + ", d));
+}
+
+TEST(InternalLogDeathTest, FailingCheck) {
+  EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_CHECK(1 == 0, "explanation"),
+                            kExpectedDeathOutput);
+}
+
+TEST(InternalLogDeathTest, LogFatal) {
+  EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_LOG(FATAL, "my dog has fleas"),
+                            kExpectedDeathOutput);
+}
+
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/compiler_config_setting.bzl b/third_party/abseil-cpp/absl/compiler_config_setting.bzl
new file mode 100644
index 0000000..b77c4f5
--- /dev/null
+++ b/third_party/abseil-cpp/absl/compiler_config_setting.bzl
@@ -0,0 +1,39 @@
+#
+# Copyright 2018 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Creates config_setting that allows selecting based on 'compiler' value."""
+
+def create_llvm_config(name, visibility):
+  # The "do_not_use_tools_cpp_compiler_present" attribute exists to
+  # distinguish between older versions of Bazel that do not support
+  # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
+  # In the future, the only way to select on the compiler will be through
+  # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
+  # be removed.
+  if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
+    native.config_setting(
+      name = name,
+      flag_values = {
+          "@bazel_tools//tools/cpp:compiler": "llvm",
+      },
+      visibility = visibility,
+    )
+  else:
+    native.config_setting(
+        name = name,
+        values = {"compiler": "llvm"},
+        visibility = visibility,
+    )
diff --git a/third_party/abseil-cpp/absl/container/BUILD.bazel b/third_party/abseil-cpp/absl/container/BUILD.bazel
index 07df367..6d5c958 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -26,10 +26,30 @@
 licenses(["notice"])  # Apache 2.0
 
 cc_library(
+    name = "compressed_tuple",
+    hdrs = ["internal/compressed_tuple.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/utility",
+    ],
+)
+
+cc_test(
+    name = "compressed_tuple_test",
+    srcs = ["internal/compressed_tuple_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":compressed_tuple",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "fixed_array",
     hdrs = ["fixed_array.h"],
     copts = ABSL_DEFAULT_COPTS,
     deps = [
+        ":compressed_tuple",
         "//absl/algorithm",
         "//absl/base:core_headers",
         "//absl/base:dynamic_annotations",
diff --git a/third_party/abseil-cpp/absl/container/BUILD.gn b/third_party/abseil-cpp/absl/container/BUILD.gn
index a00eaf4b..001a2a3 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.gn
+++ b/third_party/abseil-cpp/absl/container/BUILD.gn
@@ -14,6 +14,21 @@
   visibility = [ "*" ]
 }
 
+source_set("compressed_tuple") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/compressed_tuple.h",
+  ]
+  deps = [
+    "../utility",
+  ]
+}
+
 source_set("fixed_array") {
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [
@@ -25,6 +40,7 @@
     "fixed_array.h",
   ]
   deps = [
+    ":compressed_tuple",
     "../algorithm",
     "../base:core_headers",
     "../base:dynamic_annotations",
diff --git a/third_party/abseil-cpp/absl/container/CMakeLists.txt b/third_party/abseil-cpp/absl/container/CMakeLists.txt
index d580b48..123e4c4 100644
--- a/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -52,7 +52,6 @@
     ${TEST_INSTANCE_TRACKER_LIB_SRC}
   PUBLIC_LIBRARIES
     absl::container
-  DISABLE_INSTALL
 )
 
 
diff --git a/third_party/abseil-cpp/absl/container/fixed_array.h b/third_party/abseil-cpp/absl/container/fixed_array.h
index 708c615..182258f 100644
--- a/third_party/abseil-cpp/absl/container/fixed_array.h
+++ b/third_party/abseil-cpp/absl/container/fixed_array.h
@@ -47,6 +47,7 @@
 #include "absl/base/macros.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
+#include "absl/container/internal/compressed_tuple.h"
 #include "absl/memory/memory.h"
 
 namespace absl {
@@ -76,73 +77,99 @@
 // heap allocation, it will do so with global `::operator new[]()` and
 // `::operator delete[]()`, even if T provides class-scope overrides for these
 // operators.
-template <typename T, size_t inlined = kFixedArrayUseDefault>
+template <typename T, size_t N = kFixedArrayUseDefault,
+          typename A = std::allocator<T>>
 class FixedArray {
   static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
                 "Arrays with unknown bounds cannot be used with FixedArray.");
+
   static constexpr size_t kInlineBytesDefault = 256;
 
+  using AllocatorTraits = std::allocator_traits<A>;
   // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
   // but this seems to be mostly pedantic.
   template <typename Iterator>
   using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
       typename std::iterator_traits<Iterator>::iterator_category,
       std::forward_iterator_tag>::value>;
+  static constexpr bool NoexceptCopyable() {
+    return std::is_nothrow_copy_constructible<StorageElement>::value &&
+           absl::allocator_is_nothrow<allocator_type>::value;
+  }
+  static constexpr bool NoexceptMovable() {
+    return std::is_nothrow_move_constructible<StorageElement>::value &&
+           absl::allocator_is_nothrow<allocator_type>::value;
+  }
+  static constexpr bool DefaultConstructorIsNonTrivial() {
+    return !absl::is_trivially_default_constructible<StorageElement>::value;
+  }
 
  public:
-  using value_type = T;
-  using iterator = T*;
-  using const_iterator = const T*;
+  using allocator_type = typename AllocatorTraits::allocator_type;
+  using value_type = typename allocator_type::value_type;
+  using pointer = typename allocator_type::pointer;
+  using const_pointer = typename allocator_type::const_pointer;
+  using reference = typename allocator_type::reference;
+  using const_reference = typename allocator_type::const_reference;
+  using size_type = typename allocator_type::size_type;
+  using difference_type = typename allocator_type::difference_type;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-  using reference = T&;
-  using const_reference = const T&;
-  using pointer = T*;
-  using const_pointer = const T*;
-  using difference_type = ptrdiff_t;
-  using size_type = size_t;
 
   static constexpr size_type inline_elements =
-      inlined == kFixedArrayUseDefault
-          ? kInlineBytesDefault / sizeof(value_type)
-          : inlined;
+      (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
+                                  : static_cast<size_type>(N));
 
-  FixedArray(const FixedArray& other)
-      : FixedArray(other.begin(), other.end()) {}
+  FixedArray(
+      const FixedArray& other,
+      const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable())
+      : FixedArray(other.begin(), other.end(), a) {}
 
-  FixedArray(FixedArray&& other) noexcept(
-      absl::conjunction<absl::allocator_is_nothrow<std::allocator<value_type>>,
-                        std::is_nothrow_move_constructible<value_type>>::value)
+  FixedArray(
+      FixedArray&& other,
+      const allocator_type& a = allocator_type()) noexcept(NoexceptMovable())
       : FixedArray(std::make_move_iterator(other.begin()),
-                   std::make_move_iterator(other.end())) {}
+                   std::make_move_iterator(other.end()), a) {}
 
   // Creates an array object that can store `n` elements.
   // Note that trivially constructible elements will be uninitialized.
-  explicit FixedArray(size_type n) : storage_(n) {
-    absl::memory_internal::uninitialized_default_construct_n(storage_.begin(),
-                                                             size());
+  explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
+      : storage_(n, a) {
+    if (DefaultConstructorIsNonTrivial()) {
+      memory_internal::ConstructStorage(storage_.alloc(), storage_.begin(),
+                                        storage_.end());
+    }
   }
 
   // Creates an array initialized with `n` copies of `val`.
-  FixedArray(size_type n, const value_type& val) : storage_(n) {
-    std::uninitialized_fill_n(data(), size(), val);
+  FixedArray(size_type n, const value_type& val,
+             const allocator_type& a = allocator_type())
+      : storage_(n, a) {
+    memory_internal::ConstructStorage(storage_.alloc(), storage_.begin(),
+                                      storage_.end(), val);
   }
 
+  // Creates an array initialized with the size and contents of `init_list`.
+  FixedArray(std::initializer_list<value_type> init_list,
+             const allocator_type& a = allocator_type())
+      : FixedArray(init_list.begin(), init_list.end(), a) {}
+
   // Creates an array initialized with the elements from the input
   // range. The array's size will always be `std::distance(first, last)`.
   // REQUIRES: Iterator must be a forward_iterator or better.
   template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
-  FixedArray(Iterator first, Iterator last)
-      : storage_(std::distance(first, last)) {
-    std::uninitialized_copy(first, last, data());
+  FixedArray(Iterator first, Iterator last,
+             const allocator_type& a = allocator_type())
+      : storage_(std::distance(first, last), a) {
+    memory_internal::CopyToStorageFromRange(storage_.alloc(), storage_.begin(),
+                                            first, last);
   }
 
-  FixedArray(std::initializer_list<value_type> init_list)
-      : FixedArray(init_list.begin(), init_list.end()) {}
-
   ~FixedArray() noexcept {
-    for (const StorageElement& cur : storage_) {
-      cur.~StorageElement();
+    for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
+      AllocatorTraits::destroy(*storage_.alloc(), cur);
     }
   }
 
@@ -332,7 +359,6 @@
   friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
     return !(lhs < rhs);
   }
-
  private:
   // StorageElement
   //
@@ -364,6 +390,8 @@
   using StorageElement =
       absl::conditional_t<std::is_array<value_type>::value,
                           StorageElementWrapper<value_type>, value_type>;
+  using StorageElementBuffer =
+      absl::aligned_storage_t<sizeof(StorageElement), alignof(StorageElement)>;
 
   static pointer AsValueType(pointer ptr) { return ptr; }
   static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
@@ -374,9 +402,6 @@
   static_assert(alignof(StorageElement) == alignof(value_type), "");
 
   struct NonEmptyInlinedStorage {
-    using StorageElementBuffer =
-        absl::aligned_storage_t<sizeof(StorageElement),
-                                alignof(StorageElement)>;
     StorageElement* data() {
       return reinterpret_cast<StorageElement*>(inlined_storage_.data());
     }
@@ -386,8 +411,8 @@
     void* RedzoneEnd() { return &redzone_end_ + 1; }
 #endif  // ADDRESS_SANITIZER
 
-    void AnnotateConstruct(size_t);
-    void AnnotateDestruct(size_t);
+    void AnnotateConstruct(size_type);
+    void AnnotateDestruct(size_type);
 
     ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
     std::array<StorageElementBuffer, inline_elements> inlined_storage_;
@@ -396,8 +421,8 @@
 
   struct EmptyInlinedStorage {
     StorageElement* data() { return nullptr; }
-    void AnnotateConstruct(size_t) {}
-    void AnnotateDestruct(size_t) {}
+    void AnnotateConstruct(size_type) {}
+    void AnnotateDestruct(size_type) {}
   };
 
   using InlinedStorage =
@@ -414,48 +439,57 @@
   //
   class Storage : public InlinedStorage {
    public:
-    explicit Storage(size_type n) : data_(CreateStorage(n)), size_(n) {}
+    Storage(size_type n, const allocator_type& a)
+        : size_alloc_(n, a), data_(InitializeData()) {}
+
     ~Storage() noexcept {
       if (UsingInlinedStorage(size())) {
-        this->AnnotateDestruct(size());
+        InlinedStorage::AnnotateDestruct(size());
       } else {
-        std::allocator<StorageElement>().deallocate(begin(), size());
+        AllocatorTraits::deallocate(*alloc(), AsValueType(begin()), size());
       }
     }
 
-    size_type size() const { return size_; }
+    size_type size() const { return size_alloc_.template get<0>(); }
     StorageElement* begin() const { return data_; }
     StorageElement* end() const { return begin() + size(); }
+    allocator_type* alloc() {
+      return std::addressof(size_alloc_.template get<1>());
+    }
 
    private:
     static bool UsingInlinedStorage(size_type n) {
       return n <= inline_elements;
     }
 
-    StorageElement* CreateStorage(size_type n) {
-      if (UsingInlinedStorage(n)) {
-        this->AnnotateConstruct(n);
+    StorageElement* InitializeData() {
+      if (UsingInlinedStorage(size())) {
+        InlinedStorage::AnnotateConstruct(size());
         return InlinedStorage::data();
       } else {
-        return std::allocator<StorageElement>().allocate(n);
+        return reinterpret_cast<StorageElement*>(
+            AllocatorTraits::allocate(*alloc(), size()));
       }
     }
 
-    StorageElement* const data_;
-    const size_type size_;
+    // `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
+    container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
+    StorageElement* data_;
   };
 
-  const Storage storage_;
+  Storage storage_;
 };
 
-template <typename T, size_t N>
-constexpr size_t FixedArray<T, N>::inline_elements;
+template <typename T, size_t N, typename A>
+constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
 
-template <typename T, size_t N>
-constexpr size_t FixedArray<T, N>::kInlineBytesDefault;
+template <typename T, size_t N, typename A>
+constexpr typename FixedArray<T, N, A>::size_type
+    FixedArray<T, N, A>::inline_elements;
 
-template <typename T, size_t N>
-void FixedArray<T, N>::NonEmptyInlinedStorage::AnnotateConstruct(size_t n) {
+template <typename T, size_t N, typename A>
+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
+    typename FixedArray<T, N, A>::size_type n) {
 #ifdef ADDRESS_SANITIZER
   if (!n) return;
   ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
@@ -464,8 +498,9 @@
   static_cast<void>(n);  // Mark used when not in asan mode
 }
 
-template <typename T, size_t N>
-void FixedArray<T, N>::NonEmptyInlinedStorage::AnnotateDestruct(size_t n) {
+template <typename T, size_t N, typename A>
+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
+    typename FixedArray<T, N, A>::size_type n) {
 #ifdef ADDRESS_SANITIZER
   if (!n) return;
   ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
@@ -473,6 +508,5 @@
 #endif                   // ADDRESS_SANITIZER
   static_cast<void>(n);  // Mark used when not in asan mode
 }
-
 }  // namespace absl
 #endif  // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/third_party/abseil-cpp/absl/container/fixed_array_test.cc b/third_party/abseil-cpp/absl/container/fixed_array_test.cc
index 2142132..b07ebcb 100644
--- a/third_party/abseil-cpp/absl/container/fixed_array_test.cc
+++ b/third_party/abseil-cpp/absl/container/fixed_array_test.cc
@@ -15,9 +15,11 @@
 #include "absl/container/fixed_array.h"
 
 #include <stdio.h>
+#include <cstring>
 #include <list>
 #include <memory>
 #include <numeric>
+#include <scoped_allocator>
 #include <stdexcept>
 #include <string>
 #include <vector>
@@ -607,6 +609,216 @@
   empty.fill(fill_val);
 }
 
+// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
+#ifndef __GNUC__
+TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
+  using T = char;
+  constexpr auto capacity = 10;
+  using FixedArrType = absl::FixedArray<T, capacity>;
+  using FixedArrBuffType =
+      absl::aligned_storage_t<sizeof(FixedArrType), alignof(FixedArrType)>;
+  constexpr auto scrubbed_bits = 0x95;
+  constexpr auto length = capacity / 2;
+
+  FixedArrBuffType buff;
+  std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType));
+
+  FixedArrType* arr =
+      ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
+  EXPECT_THAT(*arr, testing::Each(scrubbed_bits));
+  arr->~FixedArrType();
+}
+#endif  // __GNUC__
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator : public std::allocator<T> {
+ public:
+  using Alloc = std::allocator<T>;
+  using pointer = typename Alloc::pointer;
+  using size_type = typename Alloc::size_type;
+
+  CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {}
+  explicit CountingAllocator(int64_t* b)
+      : bytes_used_(b), instance_count_(nullptr) {}
+  CountingAllocator(int64_t* b, int64_t* a)
+      : bytes_used_(b), instance_count_(a) {}
+
+  template <typename U>
+  explicit CountingAllocator(const CountingAllocator<U>& x)
+      : Alloc(x),
+        bytes_used_(x.bytes_used_),
+        instance_count_(x.instance_count_) {}
+
+  pointer allocate(size_type n, const void* const hint = nullptr) {
+    assert(bytes_used_ != nullptr);
+    *bytes_used_ += n * sizeof(T);
+    return Alloc::allocate(n, hint);
+  }
+
+  void deallocate(pointer p, size_type n) {
+    Alloc::deallocate(p, n);
+    assert(bytes_used_ != nullptr);
+    *bytes_used_ -= n * sizeof(T);
+  }
+
+  template <typename... Args>
+  void construct(pointer p, Args&&... args) {
+    Alloc::construct(p, absl::forward<Args>(args)...);
+    if (instance_count_) {
+      *instance_count_ += 1;
+    }
+  }
+
+  void destroy(pointer p) {
+    Alloc::destroy(p);
+    if (instance_count_) {
+      *instance_count_ -= 1;
+    }
+  }
+
+  template <typename U>
+  class rebind {
+   public:
+    using other = CountingAllocator<U>;
+  };
+
+  int64_t* bytes_used_;
+  int64_t* instance_count_;
+};
+
+TEST(AllocatorSupportTest, CountInlineAllocations) {
+  constexpr size_t inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+  int64_t allocated = 0;
+  int64_t active_instances = 0;
+
+  {
+    const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+    Alloc alloc(&allocated, &active_instances);
+
+    AllocFxdArr arr(ia, ia + inlined_size, alloc);
+    static_cast<void>(arr);
+  }
+
+  EXPECT_EQ(allocated, 0);
+  EXPECT_EQ(active_instances, 0);
+}
+
+TEST(AllocatorSupportTest, CountOutoflineAllocations) {
+  constexpr size_t inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+  int64_t allocated = 0;
+  int64_t active_instances = 0;
+
+  {
+    const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
+    Alloc alloc(&allocated, &active_instances);
+
+    AllocFxdArr arr(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
+
+    EXPECT_EQ(allocated, arr.size() * sizeof(int));
+    static_cast<void>(arr);
+  }
+
+  EXPECT_EQ(active_instances, 0);
+}
+
+TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
+  constexpr size_t inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+  int64_t allocated1 = 0;
+  int64_t allocated2 = 0;
+  int64_t active_instances = 0;
+  Alloc alloc(&allocated1, &active_instances);
+  Alloc alloc2(&allocated2, &active_instances);
+
+  {
+    int initial_value = 1;
+
+    AllocFxdArr arr1(inlined_size / 2, initial_value, alloc);
+
+    EXPECT_EQ(allocated1, 0);
+
+    AllocFxdArr arr2(arr1, alloc2);
+
+    EXPECT_EQ(allocated2, 0);
+    static_cast<void>(arr1);
+    static_cast<void>(arr2);
+  }
+
+  EXPECT_EQ(active_instances, 0);
+}
+
+TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
+  constexpr size_t inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+  int64_t allocated1 = 0;
+  int64_t allocated2 = 0;
+  int64_t active_instances = 0;
+  Alloc alloc(&allocated1, &active_instances);
+  Alloc alloc2(&allocated2, &active_instances);
+
+  {
+    int initial_value = 1;
+
+    AllocFxdArr arr1(inlined_size * 2, initial_value, alloc);
+
+    EXPECT_EQ(allocated1, arr1.size() * sizeof(int));
+
+    AllocFxdArr arr2(arr1, alloc2);
+
+    EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int));
+    static_cast<void>(arr1);
+    static_cast<void>(arr2);
+  }
+
+  EXPECT_EQ(active_instances, 0);
+}
+
+TEST(AllocatorSupportTest, SizeValAllocConstructor) {
+  using testing::AllOf;
+  using testing::Each;
+  using testing::SizeIs;
+
+  constexpr size_t inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+  {
+    auto len = inlined_size / 2;
+    auto val = 0;
+    int64_t allocated = 0;
+    AllocFxdArr arr(len, val, Alloc(&allocated));
+
+    EXPECT_EQ(allocated, 0);
+    EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
+  }
+
+  {
+    auto len = inlined_size * 2;
+    auto val = 0;
+    int64_t allocated = 0;
+    AllocFxdArr arr(len, val, Alloc(&allocated));
+
+    EXPECT_EQ(allocated, len * sizeof(int));
+    EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
+  }
+}
+
 #ifdef ADDRESS_SANITIZER
 TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
   absl::FixedArray<int, 32> a(10);
@@ -655,5 +867,4 @@
   EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
 }
 #endif  // ADDRESS_SANITIZER
-
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector.h b/third_party/abseil-cpp/absl/container/inlined_vector.h
index 03660f1..ca36fd3 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector.h
+++ b/third_party/abseil-cpp/absl/container/inlined_vector.h
@@ -626,14 +626,18 @@
   // It holds whether the vector is allocated or not in the lowest bit.
   // The size is held in the high bits:
   //   size_ = (size << 1) | is_allocated;
+  //
+  // Maintainer's Note: size_type is user defined. The contract is limited to
+  // arithmetic operators to avoid depending on compliant overloaded bitwise
+  // operators.
   class Tag {
    public:
     Tag() : size_(0) {}
-    size_type size() const { return size_ >> 1; }
-    void add_size(size_type n) { size_ += n << 1; }
-    void set_inline_size(size_type n) { size_ = n << 1; }
-    void set_allocated_size(size_type n) { size_ = (n << 1) | 1; }
-    bool allocated() const { return size_ & 1; }
+    size_type size() const { return size_ / 2; }
+    void add_size(size_type n) { size_ += n * 2; }
+    void set_inline_size(size_type n) { size_ = n * 2; }
+    void set_allocated_size(size_type n) { size_ = (n * 2) + 1; }
+    bool allocated() const { return size_ % 2; }
 
    private:
     size_type size_;
@@ -689,11 +693,14 @@
     new (&rep_.allocation_storage.allocation) Allocation(allocation);
   }
 
+  // TODO(absl-team): investigate whether the reinterpret_cast is appropriate.
   value_type* inlined_space() {
-    return reinterpret_cast<value_type*>(&rep_.inlined_storage.inlined);
+    return reinterpret_cast<value_type*>(
+        std::addressof(rep_.inlined_storage.inlined[0]));
   }
   const value_type* inlined_space() const {
-    return reinterpret_cast<const value_type*>(&rep_.inlined_storage.inlined);
+    return reinterpret_cast<const value_type*>(
+        std::addressof(rep_.inlined_storage.inlined[0]));
   }
 
   value_type* allocated_space() { return allocation().buffer(); }
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
index f81fad5..196a1be 100644
--- a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
+++ b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
@@ -1788,5 +1788,4 @@
     EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
   }
 }
-
 }  // anonymous namespace
diff --git a/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h b/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h
new file mode 100644
index 0000000..cc52614f
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h
@@ -0,0 +1,175 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Helper class to perform the Empty Base Optimization.
+// Ts can contain classes and non-classes, empty or not. For the ones that
+// are empty classes, we perform the optimization. If all types in Ts are empty
+// classes, then CompressedTuple<Ts...> is itself an empty class.
+//
+// To access the members, use member get<N>() function.
+//
+// Eg:
+//   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
+//                                                                    t3);
+//   assert(value.get<0>() == 7);
+//   T1& t1 = value.get<1>();
+//   const T2& t2 = value.get<2>();
+//   ...
+//
+// http://en.cppreference.com/w/cpp/language/ebo
+
+#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
+#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/utility/utility.h"
+
+#ifdef _MSC_VER
+// We need to mark these classes with this declspec to ensure that
+// CompressedTuple happens.
+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
+#else  // _MSC_VER
+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+#endif  // _MSC_VER
+
+namespace absl {
+namespace container_internal {
+
+template <typename... Ts>
+class CompressedTuple;
+
+namespace internal_compressed_tuple {
+
+template <typename D, size_t I>
+struct Elem;
+template <typename... B, size_t I>
+struct Elem<CompressedTuple<B...>, I>
+    : std::tuple_element<I, std::tuple<B...>> {};
+template <typename D, size_t I>
+using ElemT = typename Elem<D, I>::type;
+
+// Use the __is_final intrinsic if available. Where it's not available, classes
+// declared with the 'final' specifier cannot be used as CompressedTuple
+// elements.
+// TODO(sbenza): Replace this with std::is_final in C++14.
+template <typename T>
+constexpr bool IsFinal() {
+#if defined(__clang__) || defined(__GNUC__)
+  return __is_final(T);
+#else
+  return false;
+#endif
+}
+
+template <typename T>
+constexpr bool ShouldUseBase() {
+  return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>();
+}
+
+// The storage class provides two specializations:
+//  - For empty classes, it stores T as a base class.
+//  - For everything else, it stores T as a member.
+template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()>
+struct Storage {
+  using T = ElemT<D, I>;
+  T value;
+  constexpr Storage() = default;
+  explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
+  constexpr const T& get() const { return value; }
+  T& get() { return value; }
+};
+
+template <typename D, size_t I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
+    : ElemT<D, I> {
+  using T = internal_compressed_tuple::ElemT<D, I>;
+  constexpr Storage() = default;
+  explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
+  constexpr const T& get() const { return *this; }
+  T& get() { return *this; }
+};
+
+template <typename D, typename I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
+
+template <typename... Ts, size_t... I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+    CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>>
+    // We use the dummy identity function through std::integral_constant to
+    // convince MSVC of accepting and expanding I in that context. Without it
+    // you would get:
+    //   error C3548: 'I': parameter pack cannot be used in this context
+    : Storage<CompressedTuple<Ts...>,
+              std::integral_constant<size_t, I>::value>... {
+  constexpr CompressedTupleImpl() = default;
+  explicit constexpr CompressedTupleImpl(Ts&&... args)
+      : Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {}
+};
+
+}  // namespace internal_compressed_tuple
+
+// Helper class to perform the Empty Base Class Optimization.
+// Ts can contain classes and non-classes, empty or not. For the ones that
+// are empty classes, we perform the CompressedTuple. If all types in Ts are
+// empty classes, then CompressedTuple<Ts...> is itself an empty class.
+//
+// To access the members, use member .get<N>() function.
+//
+// Eg:
+//   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
+//                                                                    t3);
+//   assert(value.get<0>() == 7);
+//   T1& t1 = value.get<1>();
+//   const T2& t2 = value.get<2>();
+//   ...
+//
+// http://en.cppreference.com/w/cpp/language/ebo
+template <typename... Ts>
+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
+    : private internal_compressed_tuple::CompressedTupleImpl<
+          CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> {
+ private:
+  template <int I>
+  using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
+
+ public:
+  constexpr CompressedTuple() = default;
+  explicit constexpr CompressedTuple(Ts... base)
+      : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
+
+  template <int I>
+  ElemT<I>& get() {
+    return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
+  }
+
+  template <int I>
+  constexpr const ElemT<I>& get() const {
+    return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
+  }
+};
+
+// Explicit specialization for a zero-element tuple
+// (needed to avoid ambiguous overloads for the default constructor).
+template <>
+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
+
+}  // namespace container_internal
+}  // namespace absl
+
+#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+
+#endif  // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
diff --git a/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc b/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc
new file mode 100644
index 0000000..45030c6
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc
@@ -0,0 +1,166 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/compressed_tuple.h"
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace container_internal {
+namespace {
+
+template <int>
+struct Empty {};
+
+template <typename T>
+struct NotEmpty {
+  T value;
+};
+
+template <typename T, typename U>
+struct TwoValues {
+  T value1;
+  U value2;
+};
+
+TEST(CompressedTupleTest, Sizeof) {
+  EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int>));
+  EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>>));
+  EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>, Empty<1>>));
+  EXPECT_EQ(sizeof(int),
+            sizeof(CompressedTuple<int, Empty<0>, Empty<1>, Empty<2>>));
+
+  EXPECT_EQ(sizeof(TwoValues<int, double>),
+            sizeof(CompressedTuple<int, NotEmpty<double>>));
+  EXPECT_EQ(sizeof(TwoValues<int, double>),
+            sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>>));
+  EXPECT_EQ(sizeof(TwoValues<int, double>),
+            sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>, Empty<1>>));
+}
+
+TEST(CompressedTupleTest, Access) {
+  struct S {
+    std::string x;
+  };
+  CompressedTuple<int, Empty<0>, S> x(7, {}, S{"ABC"});
+  EXPECT_EQ(sizeof(x), sizeof(TwoValues<int, S>));
+  EXPECT_EQ(7, x.get<0>());
+  EXPECT_EQ("ABC", x.get<2>().x);
+}
+
+TEST(CompressedTupleTest, NonClasses) {
+  CompressedTuple<int, const char*> x(7, "ABC");
+  EXPECT_EQ(7, x.get<0>());
+  EXPECT_STREQ("ABC", x.get<1>());
+}
+
+TEST(CompressedTupleTest, MixClassAndNonClass) {
+  CompressedTuple<int, const char*, Empty<0>, NotEmpty<double>> x(7, "ABC", {},
+                                                                  {1.25});
+  struct Mock {
+    int v;
+    const char* p;
+    double d;
+  };
+  EXPECT_EQ(sizeof(x), sizeof(Mock));
+  EXPECT_EQ(7, x.get<0>());
+  EXPECT_STREQ("ABC", x.get<1>());
+  EXPECT_EQ(1.25, x.get<3>().value);
+}
+
+TEST(CompressedTupleTest, Nested) {
+  CompressedTuple<int, CompressedTuple<int>,
+                  CompressedTuple<int, CompressedTuple<int>>>
+      x(1, CompressedTuple<int>(2),
+        CompressedTuple<int, CompressedTuple<int>>(3, CompressedTuple<int>(4)));
+  EXPECT_EQ(1, x.get<0>());
+  EXPECT_EQ(2, x.get<1>().get<0>());
+  EXPECT_EQ(3, x.get<2>().get<0>());
+  EXPECT_EQ(4, x.get<2>().get<1>().get<0>());
+
+  CompressedTuple<Empty<0>, Empty<0>,
+                  CompressedTuple<Empty<0>, CompressedTuple<Empty<0>>>>
+      y;
+  std::set<Empty<0>*> empties{&y.get<0>(), &y.get<1>(), &y.get<2>().get<0>(),
+                              &y.get<2>().get<1>().get<0>()};
+#ifdef _MSC_VER
+  // MSVC has a bug where many instances of the same base class are layed out in
+  // the same address when using __declspec(empty_bases).
+  // This will be fixed in a future version of MSVC.
+  int expected = 1;
+#else
+  int expected = 4;
+#endif
+  EXPECT_EQ(expected, sizeof(y));
+  EXPECT_EQ(expected, empties.size());
+  EXPECT_EQ(sizeof(y), sizeof(Empty<0>) * empties.size());
+
+  EXPECT_EQ(4 * sizeof(char),
+            sizeof(CompressedTuple<CompressedTuple<char, char>,
+                                   CompressedTuple<char, char>>));
+  EXPECT_TRUE(
+      (std::is_empty<CompressedTuple<CompressedTuple<Empty<0>>,
+                                     CompressedTuple<Empty<1>>>>::value));
+}
+
+TEST(CompressedTupleTest, Reference) {
+  int i = 7;
+  std::string s = "Very long std::string that goes in the heap";
+  CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
+
+  // Sanity check. We should have not moved from `s`
+  EXPECT_EQ(s, "Very long std::string that goes in the heap");
+
+  EXPECT_EQ(x.get<0>(), x.get<1>());
+  EXPECT_NE(&x.get<0>(), &x.get<1>());
+  EXPECT_EQ(&x.get<1>(), &i);
+
+  EXPECT_EQ(x.get<2>(), x.get<3>());
+  EXPECT_NE(&x.get<2>(), &x.get<3>());
+  EXPECT_EQ(&x.get<3>(), &s);
+}
+
+TEST(CompressedTupleTest, NoElements) {
+  CompressedTuple<> x;
+  static_cast<void>(x);  // Silence -Wunused-variable.
+  EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
+}
+
+TEST(CompressedTupleTest, Constexpr) {
+  constexpr CompressedTuple<int, double, CompressedTuple<int>> x(
+      7, 1.25, CompressedTuple<int>(5));
+  constexpr int x0 = x.get<0>();
+  constexpr double x1 = x.get<1>();
+  constexpr int x2 = x.get<2>().get<0>();
+  EXPECT_EQ(x0, 7);
+  EXPECT_EQ(x1, 1.25);
+  EXPECT_EQ(x2, 5);
+}
+
+#if defined(__clang__) || defined(__GNUC__)
+TEST(CompressedTupleTest, EmptyFinalClass) {
+  struct S final {
+    int f() const { return 5; }
+  };
+  CompressedTuple<S> x;
+  EXPECT_EQ(x.get<0>().f(), 5);
+}
+#endif
+
+}  // namespace
+}  // namespace container_internal
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/copts.bzl b/third_party/abseil-cpp/absl/copts.bzl
index 20c9b61..0168ac5 100644
--- a/third_party/abseil-cpp/absl/copts.bzl
+++ b/third_party/abseil-cpp/absl/copts.bzl
@@ -31,7 +31,6 @@
     "-Wno-unused-private-field",
 ]
 
-
 # Docs on single flags is preceded by a comment.
 # Docs on groups of flags is preceded by ###.
 
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
index 4c131fe..d4b957b 100644
--- a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
+++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
@@ -252,7 +252,7 @@
       depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
 }
 
-// Called by FailureSignalHandler() to write the failure info. It is
+// Called by AbslFailureSignalHandler() to write the failure info. It is
 // called once with writerfn set to WriteToStderr() and then possibly
 // with writerfn set to the user provided function.
 static void WriteFailureInfo(int signo, void* ucontext,
@@ -278,9 +278,9 @@
 }
 
 #ifdef ABSL_HAVE_ALARM
-// FailureSignalHandler() installs this as a signal handler for
+// AbslFailureSignalHandler() installs this as a signal handler for
 // SIGALRM, then sets an alarm to be delivered to the program after a
-// set amount of time. If FailureSignalHandler() hangs for more than
+// set amount of time. If AbslFailureSignalHandler() hangs for more than
 // the alarm timeout, ImmediateAbortSignalHandler() will abort the
 // program.
 static void ImmediateAbortSignalHandler(int) {
@@ -294,11 +294,10 @@
 ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
 
 #ifndef ABSL_HAVE_SIGACTION
-static void FailureSignalHandler(int signo) {
+static void AbslFailureSignalHandler(int signo) {
   void* ucontext = nullptr;
 #else
-static void FailureSignalHandler(int signo, siginfo_t*,
-                                 void* ucontext) {
+static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
 #endif
 
   const GetTidType this_tid = absl::base_internal::GetTID();
@@ -308,10 +307,10 @@
           std::memory_order_acq_rel, std::memory_order_relaxed)) {
     ABSL_RAW_LOG(
         ERROR,
-        "Signal %d raised at PC=%p while already in FailureSignalHandler()",
+        "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()",
         signo, absl::debugging_internal::GetProgramCounter(ucontext));
     if (this_tid != previous_failed_tid) {
-      // Another thread is already in FailureSignalHandler(), so wait
+      // Another thread is already in AbslFailureSignalHandler(), so wait
       // a bit for it to finish. If the other thread doesn't kill us,
       // we do so after sleeping.
       PortableSleepForSeconds(3);
@@ -349,7 +348,7 @@
 void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
   fsh_options = options;
   for (auto& it : failure_signal_data) {
-    InstallOneFailureHandler(&it, FailureSignalHandler);
+    InstallOneFailureHandler(&it, AbslFailureSignalHandler);
   }
 }
 
diff --git a/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc b/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
index 8434709f..faf8883 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
+++ b/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
@@ -52,6 +52,10 @@
     return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
 #elif defined(__powerpc__)
     return reinterpret_cast<void*>(context->uc_mcontext.regs->nip);
+#elif defined(__s390__) && !defined(__s390x__)
+    return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
+#elif defined(__s390__) && defined(__s390x__)
+    return reinterpret_cast<void*>(context->uc_mcontext.psw.addr);
 #elif defined(__x86_64__)
     if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
       return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
index 48adfcc..dd713da 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
+++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
@@ -21,26 +21,16 @@
 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 
-// First, test platforms which only support a stub.
-#if ABSL_STACKTRACE_INL_HEADER
+#if defined(ABSL_STACKTRACE_INL_HEADER)
 #error ABSL_STACKTRACE_INL_HEADER cannot be directly set
-#elif defined(__native_client__) || defined(__APPLE__) || \
-    defined(__FreeBSD__) || defined(__ANDROID__) || defined(__myriad2__) || \
-    defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__)
-#define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
 
-// Next, test for Mips and Windows.
-// TODO(marmstrong): Mips case, remove the check for ABSL_STACKTRACE_INL_HEADER
-#elif defined(__mips__) && !defined(ABSL_STACKTRACE_INL_HEADER)
-#define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-#elif defined(_WIN32)  // windows
+#elif defined(_WIN32)
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_win32-inl.inc"
 
-// Finally, test NO_FRAME_POINTER.
-#elif !defined(NO_FRAME_POINTER)
+#elif defined(__linux__) && !defined(__ANDROID__)
+
+#if !defined(NO_FRAME_POINTER)
 # if defined(__i386__) || defined(__x86_64__)
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_x86-inl.inc"
@@ -53,22 +43,27 @@
 # elif defined(__arm__)
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_arm-inl.inc"
+# else
+#define ABSL_STACKTRACE_INL_HEADER \
+   "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
 # endif
 #else  // defined(NO_FRAME_POINTER)
 # if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
 #define ABSL_STACKTRACE_INL_HEADER \
-    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+    "absl/debugging/internal/stacktrace_generic-inl.inc"
 # elif defined(__ppc__) || defined(__PPC__)
-//  Use glibc's backtrace.
 #define ABSL_STACKTRACE_INL_HEADER \
     "absl/debugging/internal/stacktrace_generic-inl.inc"
-# elif defined(__arm__)
-#   error stacktrace without frame pointer is not supported on ARM
+# else
+#define ABSL_STACKTRACE_INL_HEADER \
+   "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
 # endif
 #endif  // NO_FRAME_POINTER
 
-#if !defined(ABSL_STACKTRACE_INL_HEADER)
-#error Not supported yet
+#else
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+
 #endif
 
 #endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
index 297bdad..860ac2b3 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -31,6 +31,8 @@
 #include <cstdint>
 #include <cstdio>
 
+#include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
 #include "absl/base/port.h"
 #include "absl/debugging/stacktrace.h"
 #include "absl/debugging/internal/address_is_readable.h"
@@ -150,8 +152,9 @@
 }
 
 // This ensures that absl::GetStackTrace sets up the Link Register properly.
-void StacktracePowerPCDummyFunction() __attribute__((noinline));
-void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
+ABSL_ATTRIBUTE_NOINLINE static void AbslStacktracePowerPCDummyFunction() {
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
 
 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
 ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
@@ -176,7 +179,7 @@
   // want here.  While the compiler will always(?) set up LR for
   // subroutine calls, it may not for leaf functions (such as this one).
   // This routine forces the compiler (at least gcc) to push it anyway.
-  StacktracePowerPCDummyFunction();
+  AbslStacktracePowerPCDummyFunction();
 
   // The LR save area is used by the callee, so the top entry is bogus.
   skip_count++;
diff --git a/third_party/abseil-cpp/absl/memory/memory.h b/third_party/abseil-cpp/absl/memory/memory.h
index c43e156..c7caf8b 100644
--- a/third_party/abseil-cpp/absl/memory/memory.h
+++ b/third_party/abseil-cpp/absl/memory/memory.h
@@ -83,7 +83,11 @@
 
 }  // namespace memory_internal
 
-#if __cplusplus >= 201402L || defined(_MSC_VER)
+// gcc 4.8 has __cplusplus at 201301 but doesn't define make_unique.  Other
+// supported compilers either just define __cplusplus as 201103 but have
+// make_unique (msvc), or have make_unique whenever __cplusplus > 201103 (clang)
+#if (__cplusplus > 201103L || defined(_MSC_VER)) && \
+    !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8)
 using std::make_unique;
 #else
 // -----------------------------------------------------------------------------
@@ -637,38 +641,56 @@
 #endif
 
 namespace memory_internal {
-// TODO(b110200014): Implement proper backports
-template <typename ForwardIt>
-void DefaultConstruct(ForwardIt it) {
-  using value_type = typename std::iterator_traits<ForwardIt>::value_type;
-  ::new (static_cast<void*>(std::addressof(*it))) value_type;
-}  // namespace memory_internal
-
 #ifdef ABSL_HAVE_EXCEPTIONS
-template <typename ForwardIt, typename Size>
-void uninitialized_default_construct_n(ForwardIt first, Size size) {
-  for (ForwardIt cur = first; size > 0; static_cast<void>(++cur), --size) {
+template <typename Allocator, typename StorageElement, typename... Args>
+void ConstructStorage(Allocator* alloc, StorageElement* first,
+                      StorageElement* last, const Args&... args) {
+  for (StorageElement* cur = first; cur != last; ++cur) {
     try {
-      absl::memory_internal::DefaultConstruct(cur);
+      std::allocator_traits<Allocator>::construct(*alloc, cur, args...);
     } catch (...) {
-      using value_type = typename std::iterator_traits<ForwardIt>::value_type;
-      for (; first != cur; ++first) {
-        first->~value_type();
+      while (cur != first) {
+        --cur;
+        std::allocator_traits<Allocator>::destroy(*alloc, cur);
+      }
+      throw;
+    }
+  }
+}
+template <typename Allocator, typename StorageElement, typename Iterator>
+void CopyToStorageFromRange(Allocator* alloc, StorageElement* destination,
+                            Iterator first, Iterator last) {
+  for (StorageElement* cur = destination; first != last;
+       static_cast<void>(++cur), static_cast<void>(++first)) {
+    try {
+      std::allocator_traits<Allocator>::construct(*alloc, cur, *first);
+    } catch (...) {
+      while (cur != destination) {
+        --cur;
+        std::allocator_traits<Allocator>::destroy(*alloc, cur);
       }
       throw;
     }
   }
 }
 #else   // ABSL_HAVE_EXCEPTIONS
-template <typename ForwardIt, typename Size>
-void uninitialized_default_construct_n(ForwardIt first, Size size) {
-  for (; size > 0; static_cast<void>(++first), --size) {
-    absl::memory_internal::DefaultConstruct(first);
+template <typename Allocator, typename StorageElement, typename... Args>
+void ConstructStorage(Allocator* alloc, StorageElement* first,
+                      StorageElement* last, const Args&... args) {
+  for (; first != last; ++first) {
+    std::allocator_traits<Allocator>::construct(*alloc, first, args...);
+  }
+}
+template <typename Allocator, typename StorageElement, typename Iterator>
+void CopyToStorageFromRange(Allocator* alloc, StorageElement* destination,
+                            Iterator first, Iterator last) {
+  for (; first != last;
+       static_cast<void>(++destination), static_cast<void>(++first)) {
+    std::allocator_traits<Allocator>::construct(*alloc, destination, *first);
   }
 }
 #endif  // ABSL_HAVE_EXCEPTIONS
 }  // namespace memory_internal
-
 }  // namespace absl
 
 #endif  // ABSL_MEMORY_MEMORY_H_
diff --git a/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc b/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc
index fb8b561..d1f6e84 100644
--- a/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc
+++ b/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc
@@ -48,16 +48,5 @@
   }));
 }
 
-TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) {
-  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
-                  .WithInitialValue(ThrowerList{})
-                  .WithOperation([&](ThrowerList* list_ptr) {
-                    absl::memory_internal::uninitialized_default_construct_n(
-                        list_ptr->data(), kLength);
-                  })
-                  .WithInvariants([&](...) { return true; })
-                  .Test());
-}
-
 }  // namespace
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/memory/memory_test.cc b/third_party/abseil-cpp/absl/memory/memory_test.cc
index 8ff1945d..dee9b486 100644
--- a/third_party/abseil-cpp/absl/memory/memory_test.cc
+++ b/third_party/abseil-cpp/absl/memory/memory_test.cc
@@ -611,47 +611,4 @@
   EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
 }
 
-TEST(MemoryInternal, UninitDefaultConstructNTrivial) {
-  constexpr int kInitialValue = 123;
-  constexpr int kExpectedValue = kInitialValue;  // Expect no-op behavior
-  constexpr int len = 5;
-
-  struct TestObj {
-    int val;
-  };
-  static_assert(absl::is_trivially_default_constructible<TestObj>::value, "");
-  static_assert(absl::is_trivially_destructible<TestObj>::value, "");
-
-  TestObj objs[len];
-  for (auto& obj : objs) {
-    obj.val = kInitialValue;
-  }
-
-  absl::memory_internal::uninitialized_default_construct_n(objs, len);
-  for (auto& obj : objs) {
-    EXPECT_EQ(obj.val, kExpectedValue);
-  }
-}
-
-TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) {
-  constexpr int kInitialValue = 123;
-  constexpr int kExpectedValue = 0;  // Expect value-construction behavior
-  constexpr int len = 5;
-
-  struct TestObj {
-    int val{kExpectedValue};
-  };
-  static_assert(absl::is_trivially_destructible<TestObj>::value, "");
-
-  TestObj objs[len];
-  for (auto& obj : objs) {
-    obj.val = kInitialValue;
-  }
-
-  absl::memory_internal::uninitialized_default_construct_n(objs, len);
-  for (auto& obj : objs) {
-    EXPECT_EQ(obj.val, kExpectedValue);
-  }
-}
-
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/meta/type_traits.h b/third_party/abseil-cpp/absl/meta/type_traits.h
index c3e01fe..457b890 100644
--- a/third_party/abseil-cpp/absl/meta/type_traits.h
+++ b/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -44,6 +44,7 @@
 namespace absl {
 
 namespace type_traits_internal {
+
 template <typename... Ts>
 struct VoidTImpl {
   using type = void;
@@ -61,6 +62,49 @@
   static constexpr size_t value = Align;
 };
 
+////////////////////////////////
+// Library Fundamentals V2 TS //
+////////////////////////////////
+
+// NOTE: The `is_detected` family of templates here differ from the library
+// fundamentals specification in that for library fundamentals, `Op<Args...>` is
+// evaluated as soon as the type `is_detected<Op, Args...>` undergoes
+// substitution, regardless of whether or not the `::value` is accessed. That
+// is inconsistent with all other standard traits and prevents lazy evaluation
+// in larger contexts (such as if the `is_detected` check is a trailing argument
+// of a `conjunction`. This implementation opts to instead be lazy in the same
+// way that the standard traits are (this "defect" of the detection idiom
+// specifications has been reported).
+
+template <class Enabler, template <class...> class Op, class... Args>
+struct is_detected_impl {
+  using type = std::false_type;
+};
+
+template <template <class...> class Op, class... Args>
+struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
+  using type = std::true_type;
+};
+
+template <template <class...> class Op, class... Args>
+struct is_detected : is_detected_impl<void, Op, Args...>::type {};
+
+template <class Enabler, class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl {
+  using type = std::false_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl<
+    typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
+    To, Op, Args...> {
+  using type = std::true_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible
+    : is_detected_convertible_impl<void, To, Op, Args...>::type {};
+
 }  // namespace type_traits_internal
 
 // void_t()
@@ -263,8 +307,9 @@
 // `is_trivially_assignable<T&, const T&>`.
 template <typename T>
 struct is_trivially_copy_assignable
-    : std::integral_constant<bool, __has_trivial_assign(T) &&
-                                   std::is_copy_assignable<T>::value> {
+    : std::integral_constant<
+          bool, __has_trivial_assign(typename std::remove_reference<T>::type) &&
+                    std::is_copy_assignable<T>::value> {
 #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
  private:
   static constexpr bool compliant =
diff --git a/third_party/abseil-cpp/absl/meta/type_traits_test.cc b/third_party/abseil-cpp/absl/meta/type_traits_test.cc
index c44d1c5..81b4bd3 100644
--- a/third_party/abseil-cpp/absl/meta/type_traits_test.cc
+++ b/third_party/abseil-cpp/absl/meta/type_traits_test.cc
@@ -34,6 +34,83 @@
 
 struct Dummy {};
 
+struct ReturnType {};
+struct ConvertibleToReturnType {
+  operator ReturnType() const;  // NOLINT
+};
+
+// Unique types used as parameter types for testing the detection idiom.
+struct StructA {};
+struct StructB {};
+struct StructC {};
+
+struct TypeWithBarFunction {
+  template <class T,
+            absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0>
+  ReturnType bar(T&&, const StructB&, StructC&&) &&;  // NOLINT
+};
+
+struct TypeWithBarFunctionAndConvertibleReturnType {
+  template <class T,
+            absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0>
+  ConvertibleToReturnType bar(T&&, const StructB&, StructC&&) &&;  // NOLINT
+};
+
+template <class Class, class... Ts>
+using BarIsCallableImpl =
+    decltype(std::declval<Class>().bar(std::declval<Ts>()...));
+
+template <class Class, class... T>
+using BarIsCallable =
+    absl::type_traits_internal::is_detected<BarIsCallableImpl, Class, T...>;
+
+template <class Class, class... T>
+using BarIsCallableConv = absl::type_traits_internal::is_detected_convertible<
+    ReturnType, BarIsCallableImpl, Class, T...>;
+
+// NOTE: Test of detail type_traits_internal::is_detected.
+TEST(IsDetectedTest, BasicUsage) {
+  EXPECT_TRUE((BarIsCallable<TypeWithBarFunction, StructA&, const StructB&,
+                             StructC>::value));
+  EXPECT_TRUE(
+      (BarIsCallable<TypeWithBarFunction, StructA&, StructB&, StructC>::value));
+  EXPECT_TRUE(
+      (BarIsCallable<TypeWithBarFunction, StructA&, StructB, StructC>::value));
+
+  EXPECT_FALSE((BarIsCallable<int, StructA&, const StructB&, StructC>::value));
+  EXPECT_FALSE((BarIsCallable<TypeWithBarFunction&, StructA&, const StructB&,
+                              StructC>::value));
+  EXPECT_FALSE((BarIsCallable<TypeWithBarFunction, StructA, const StructB&,
+                              StructC>::value));
+}
+
+// NOTE: Test of detail type_traits_internal::is_detected_convertible.
+TEST(IsDetectedConvertibleTest, BasicUsage) {
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, const StructB&,
+                                 StructC>::value));
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB&,
+                                 StructC>::value));
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB,
+                                 StructC>::value));
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
+                                 StructA&, const StructB&, StructC>::value));
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
+                                 StructA&, StructB&, StructC>::value));
+  EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
+                                 StructA&, StructB, StructC>::value));
+
+  EXPECT_FALSE(
+      (BarIsCallableConv<int, StructA&, const StructB&, StructC>::value));
+  EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction&, StructA&,
+                                  const StructB&, StructC>::value));
+  EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction, StructA, const StructB&,
+                                  StructC>::value));
+  EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType&,
+                                  StructA&, const StructB&, StructC>::value));
+  EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
+                                  StructA, const StructB&, StructC>::value));
+}
+
 TEST(VoidTTest, BasicUsage) {
   StaticAssertTypeEq<void, absl::void_t<Dummy>>();
   StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>();
@@ -528,6 +605,10 @@
   // Verify that arrays are not trivially copy assignable
   using int10 = int[10];
   EXPECT_FALSE(absl::is_trivially_copy_assignable<int10>::value);
+
+  // Verify that references are handled correctly
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&&>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&>::value);
 }
 
 #define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...)          \
@@ -714,8 +795,8 @@
   ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]);
 
   ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int());
-  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float));
-  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...));
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float));  // NOLINT
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...));  // NOLINT
 }
 
 struct TypeA {};
diff --git a/third_party/abseil-cpp/absl/numeric/int128.h b/third_party/abseil-cpp/absl/numeric/int128.h
index e4f39c3..2d131b8bd 100644
--- a/third_party/abseil-cpp/absl/numeric/int128.h
+++ b/third_party/abseil-cpp/absl/numeric/int128.h
@@ -31,6 +31,7 @@
 #include <cstring>
 #include <iosfwd>
 #include <limits>
+#include <utility>
 
 #include "absl/base/config.h"
 #include "absl/base/macros.h"
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel
index 3b1e067..3a5f133 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -159,6 +159,18 @@
 )
 
 cc_test(
+    name = "ascii_benchmark",
+    srcs = ["ascii_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
     name = "memutil_benchmark",
     srcs = [
         "internal/memutil.h",
diff --git a/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc b/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc
new file mode 100644
index 0000000..8dea4b8
--- /dev/null
+++ b/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc
@@ -0,0 +1,120 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/ascii.h"
+
+#include <cctype>
+#include <string>
+#include <array>
+#include <random>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+std::array<unsigned char, 256> MakeShuffledBytes() {
+  std::array<unsigned char, 256> bytes;
+  for (size_t i = 0; i < 256; ++i) bytes[i] = static_cast<unsigned char>(i);
+  std::random_device rd;
+  std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()});
+  std::mt19937 g(seed);
+  std::shuffle(bytes.begin(), bytes.end(), g);
+  return bytes;
+}
+
+template <typename Function>
+void AsciiBenchmark(benchmark::State& state, Function f) {
+  std::array<unsigned char, 256> bytes = MakeShuffledBytes();
+  size_t sum = 0;
+  for (auto _ : state) {
+    for (unsigned char b : bytes) sum += f(b) ? 1 : 0;
+  }
+  // Make a copy of `sum` before calling `DoNotOptimize` to make sure that `sum`
+  // can be put in a CPU register and not degrade performance in the loop above.
+  size_t sum2 = sum;
+  benchmark::DoNotOptimize(sum2);
+  state.SetBytesProcessed(state.iterations() * bytes.size());
+}
+
+using StdAsciiFunction = int (*)(int);
+template <StdAsciiFunction f>
+void BM_Ascii(benchmark::State& state) {
+  AsciiBenchmark(state, f);
+}
+
+using AbslAsciiIsFunction = bool (*)(unsigned char);
+template <AbslAsciiIsFunction f>
+void BM_Ascii(benchmark::State& state) {
+  AsciiBenchmark(state, f);
+}
+
+using AbslAsciiToFunction = char (*)(unsigned char);
+template <AbslAsciiToFunction f>
+void BM_Ascii(benchmark::State& state) {
+  AsciiBenchmark(state, f);
+}
+
+inline char Noop(unsigned char b) { return static_cast<char>(b); }
+
+BENCHMARK_TEMPLATE(BM_Ascii, Noop);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isalpha);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isalpha);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isdigit);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isdigit);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isalnum);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isalnum);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isspace);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isspace);
+BENCHMARK_TEMPLATE(BM_Ascii, std::ispunct);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_ispunct);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isblank);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isblank);
+BENCHMARK_TEMPLATE(BM_Ascii, std::iscntrl);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_iscntrl);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isxdigit);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isxdigit);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isprint);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isprint);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isgraph);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isgraph);
+BENCHMARK_TEMPLATE(BM_Ascii, std::isupper);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isupper);
+BENCHMARK_TEMPLATE(BM_Ascii, std::islower);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_islower);
+BENCHMARK_TEMPLATE(BM_Ascii, isascii);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isascii);
+BENCHMARK_TEMPLATE(BM_Ascii, std::tolower);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_tolower);
+BENCHMARK_TEMPLATE(BM_Ascii, std::toupper);
+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_toupper);
+
+static void BM_StrToLower(benchmark::State& state) {
+  const int size = state.range(0);
+  std::string s(size, 'X');
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::AsciiStrToLower(s));
+  }
+}
+BENCHMARK(BM_StrToLower)->Range(1, 1 << 20);
+
+static void BM_StrToUpper(benchmark::State& state) {
+  const int size = state.range(0);
+  std::string s(size, 'x');
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::AsciiStrToUpper(s));
+  }
+}
+BENCHMARK(BM_StrToUpper)->Range(1, 1 << 20);
+
+}  // namespace
diff --git a/third_party/abseil-cpp/absl/strings/escaping.h b/third_party/abseil-cpp/absl/strings/escaping.h
index 1af0afa..7f1ab96 100644
--- a/third_party/abseil-cpp/absl/strings/escaping.h
+++ b/third_party/abseil-cpp/absl/strings/escaping.h
@@ -139,7 +139,7 @@
 
 // WebSafeBase64Escape()
 //
-// Encodes a `src` std::string into a `dest` buffer using uses '-' instead of '+' and
+// Encodes a `src` std::string into a `dest` buffer using '-' instead of '+' and
 // '_' instead of '/', and without padding. This function conforms with RFC 4648
 // section 5 (base64url).
 void WebSafeBase64Escape(absl::string_view src, std::string* dest);
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
index 37952b4..6176db9 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
@@ -153,7 +153,14 @@
 
 template <typename Float, typename Int>
 constexpr bool CanFitMantissa() {
-  return std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits;
+  return
+#if defined(__clang__) && !defined(__SSE3__)
+      // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
+      // Casting from long double to uint64_t is miscompiled and drops bits.
+      (!std::is_same<Float, long double>::value ||
+       !std::is_same<Int, uint64_t>::value) &&
+#endif
+      std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits;
 }
 
 template <typename Float>
diff --git a/third_party/abseil-cpp/absl/strings/numbers_test.cc b/third_party/abseil-cpp/absl/strings/numbers_test.cc
index 24e7138c..27cc0479 100644
--- a/third_party/abseil-cpp/absl/strings/numbers_test.cc
+++ b/third_party/abseil-cpp/absl/strings/numbers_test.cc
@@ -56,16 +56,11 @@
 using testing::MatchesRegex;
 
 // Number of floats to test with.
-// 10,000,000 is a reasonable default for a test that only takes a few seconds.
+// 5,000,000 is a reasonable default for a test that only takes a few seconds.
 // 1,000,000,000+ triggers checking for all possible mantissa values for
 // double-precision tests. 2,000,000,000+ triggers checking for every possible
 // single-precision float.
-#ifdef _MSC_VER
-// Use a smaller number on MSVC to avoid test time out (1 min)
 const int kFloatNumCases = 5000000;
-#else
-const int kFloatNumCases = 10000000;
-#endif
 
 // This is a slow, brute-force routine to compute the exact base-10
 // representation of a double-precision floating-point number.  It
@@ -716,8 +711,9 @@
   }
 }
 
-// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC.
-#if defined(_MSC_VER) || defined(__APPLE__)
+// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC,
+// and WebAssembly.
+#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
 #define ABSL_MISSING_FEENABLEEXCEPT 1
 #define ABSL_MISSING_FEDISABLEEXCEPT 1
 #endif
diff --git a/third_party/abseil-cpp/absl/strings/str_format_test.cc b/third_party/abseil-cpp/absl/strings/str_format_test.cc
index fe742bf..fed75faf 100644
--- a/third_party/abseil-cpp/absl/strings/str_format_test.cc
+++ b/third_party/abseil-cpp/absl/strings/str_format_test.cc
@@ -384,8 +384,8 @@
   EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
   //     a/A - lower,upper case hex    Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
 
-// On NDK r16, there is a regression in hexfloat formatting.
-#if !defined(__NDK_MAJOR__) || __NDK_MAJOR__ != 16
+// On Android platform <=21, there is a regression in hexfloat formatting.
+#if !defined(__ANDROID_API__) || __ANDROID_API__ > 21
   EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1");  // .1 to fix MSVC output
   EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1");  // .1 to fix MSVC output
 #endif
diff --git a/third_party/abseil-cpp/absl/strings/str_split.h b/third_party/abseil-cpp/absl/strings/str_split.h
index 1f089b93..9a7be2b 100644
--- a/third_party/abseil-cpp/absl/strings/str_split.h
+++ b/third_party/abseil-cpp/absl/strings/str_split.h
@@ -373,11 +373,11 @@
 
 // StrSplit()
 //
-// Splits a given `std::string` based on the provided `Delimiter` object,
-// returning the elements within the type specified by the caller. Optionally,
-// you may also pass a `Predicate` to `StrSplit()` indicating whether to include
-// or exclude the resulting element within the final result set. (See the
-// overviews for Delimiters and Predicates above.)
+// Splits a given std::string based on the provided `Delimiter` object, returning the
+// elements within the type specified by the caller. Optionally, you may pass a
+// `Predicate` to `StrSplit()` indicating whether to include or exclude the
+// resulting element within the final result set. (See the overviews for
+// Delimiters and Predicates above.)
 //
 // Example:
 //
diff --git a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
index c19f5725..de0d7b7 100644
--- a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
@@ -34,7 +34,7 @@
 
 
 # synchronization library
-list(APPEND SYNCHRONIZATION_SRC 
+list(APPEND SYNCHRONIZATION_SRC
   "barrier.cc"
   "blocking_counter.cc"
   "internal/create_thread_identity.cc"
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h b/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
index 0d132d9..bb70800 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
+++ b/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
@@ -25,9 +25,6 @@
 #ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 
-#ifdef _WIN32
-#include <intsafe.h>
-#endif
 #include <time.h>
 #include <algorithm>
 #include <limits>
@@ -117,9 +114,14 @@
   // Windows. Callers should recognize that the return value is a
   // relative duration (it should be recomputed by calling this method
   // in the case of a spurious wakeup).
-  DWORD InMillisecondsFromNow() const {
+  // This header file may be included transitively by public header files,
+  // so we define our own DWORD and INFINITE instead of getting them from
+  // <intsafe.h> and <WinBase.h>.
+  typedef unsigned long DWord;  // NOLINT
+  DWord InMillisecondsFromNow() const {
+    constexpr DWord kInfinite = std::numeric_limits<DWord>::max();
     if (!has_timeout()) {
-      return INFINITE;
+      return kInfinite;
     }
     // The use of absl::Now() to convert from absolute time to
     // relative time means that absl::Now() cannot use anything that
@@ -131,10 +133,10 @@
           std::numeric_limits<int64_t>::max() - 999999u;
       uint64_t ms_from_now =
           (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
-      if (ms_from_now > std::numeric_limits<DWORD>::max()) {
-        return INFINITE;
+      if (ms_from_now > kInfinite) {
+        return kInfinite;
       }
-      return static_cast<DWORD>(ms_from_now);
+      return static_cast<DWord>(ms_from_now);
     }
     return 0;
   }
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index 840b9d6..83c2148 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -24,7 +24,7 @@
 // Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional
 // features:
 //   * Conditional predicates intrinsic to the `Mutex` object
-//   * Reader/writer locks, in addition to standard exclusive/writer locks
+//   * Shared/reader locks, in addition to standard exclusive/writer locks
 //   * Deadlock detection and debug support.
 //
 // The following helper classes are also defined within this file:
@@ -290,7 +290,7 @@
   // Mutex::ReaderLockWhen()
   // Mutex::WriterLockWhen()
   //
-  // Blocks until simultaneously both `cond` is `true` and this` Mutex` can
+  // Blocks until simultaneously both `cond` is `true` and this `Mutex` can
   // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
   // logically equivalent to `*Lock(); Await();` though they may have different
   // performance characteristics.
@@ -558,7 +558,7 @@
 // WriterMutexLock
 //
 // The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and
-// releases a write (exclusive) lock on a `Mutex` va RAII.
+// releases a write (exclusive) lock on a `Mutex` via RAII.
 class SCOPED_LOCKABLE WriterMutexLock {
  public:
   explicit WriterMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc b/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
index 30a5235..1e019e00 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
@@ -74,11 +74,11 @@
   mu.Unlock();
 }
 
-#ifdef THREAD_SANITIZER
-// ThreadSanitizer can't handle 8192 threads.
-constexpr int kMaxConditionWaiters = 2048;
-#else
+// Some configurations have higher thread limits than others.
+#if defined(__linux__) && !defined(THREAD_SANITIZER)
 constexpr int kMaxConditionWaiters = 8192;
+#else
+constexpr int kMaxConditionWaiters = 1024;
 #endif
 BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters);
 
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex_test.cc b/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
index 53b9378..b2820e2 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
@@ -29,6 +29,7 @@
 #include <vector>
 
 #include "gtest/gtest.h"
+#include "absl/base/attributes.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/sysinfo.h"
 #include "absl/memory/memory.h"
@@ -54,8 +55,8 @@
 // Hack to schedule a function to run on a thread pool thread after a
 // duration has elapsed.
 static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp,
-                          const std::function<void()> &func,
-                          absl::Duration after) {
+                          absl::Duration after,
+                          const std::function<void()> &func) {
   tp->Schedule([func, after] {
     absl::SleepFor(after);
     func();
@@ -1150,249 +1151,369 @@
 // and so never expires/passes, and one that will expire/pass in the near
 // future.
 
-// Encapsulate a Mutex-protected bool with its associated Condition/CondVar.
-class Cond {
- public:
-  explicit Cond(bool use_deadline) : use_deadline_(use_deadline), c_(&b_) {}
+static absl::Duration TimeoutTestAllowedSchedulingDelay() {
+  // Note: we use a function here because Microsoft Visual Studio fails to
+  // properly initialize constexpr static absl::Duration variables.
+  return absl::Milliseconds(150);
+}
 
-  void Set(bool v) {
-    absl::MutexLock lock(&mu_);
-    b_ = v;
+// Returns true if `actual_delay` is close enough to `expected_delay` to pass
+// the timeouts/deadlines test.  Otherwise, logs warnings and returns false.
+ABSL_MUST_USE_RESULT
+static bool DelayIsWithinBounds(absl::Duration expected_delay,
+                                absl::Duration actual_delay) {
+  bool pass = true;
+  // Do not allow the observed delay to be less than expected.  This may occur
+  // in practice due to clock skew or when the synchronization primitives use a
+  // different clock than absl::Now(), but these cases should be handled by the
+  // the retry mechanism in each TimeoutTest.
+  if (actual_delay < expected_delay) {
+    ABSL_RAW_LOG(WARNING,
+                 "Actual delay %s was too short, expected %s (difference %s)",
+                 absl::FormatDuration(actual_delay).c_str(),
+                 absl::FormatDuration(expected_delay).c_str(),
+                 absl::FormatDuration(actual_delay - expected_delay).c_str());
+    pass = false;
   }
-
-  bool AwaitWithTimeout(absl::Duration timeout) {
-    absl::MutexLock lock(&mu_);
-    return use_deadline_ ? mu_.AwaitWithDeadline(c_, absl::Now() + timeout)
-                         : mu_.AwaitWithTimeout(c_, timeout);
+  // If the expected delay is <= zero then allow a small error tolerance, since
+  // we do not expect context switches to occur during test execution.
+  // Otherwise, thread scheduling delays may be substantial in rare cases, so
+  // tolerate up to kTimeoutTestAllowedSchedulingDelay of error.
+  absl::Duration tolerance = expected_delay <= absl::ZeroDuration()
+                                 ? absl::Milliseconds(10)
+                                 : TimeoutTestAllowedSchedulingDelay();
+  if (actual_delay > expected_delay + tolerance) {
+    ABSL_RAW_LOG(WARNING,
+                 "Actual delay %s was too long, expected %s (difference %s)",
+                 absl::FormatDuration(actual_delay).c_str(),
+                 absl::FormatDuration(expected_delay).c_str(),
+                 absl::FormatDuration(actual_delay - expected_delay).c_str());
+    pass = false;
   }
+  return pass;
+}
 
-  bool LockWhenWithTimeout(absl::Duration timeout) {
-    bool b = use_deadline_ ? mu_.LockWhenWithDeadline(c_, absl::Now() + timeout)
-                           : mu_.LockWhenWithTimeout(c_, timeout);
-    mu_.Unlock();
-    return b;
-  }
+// Parameters for TimeoutTest, below.
+struct TimeoutTestParam {
+  // The file and line number (used for logging purposes only).
+  const char *from_file;
+  int from_line;
 
-  bool ReaderLockWhenWithTimeout(absl::Duration timeout) {
-    bool b = use_deadline_
-                 ? mu_.ReaderLockWhenWithDeadline(c_, absl::Now() + timeout)
-                 : mu_.ReaderLockWhenWithTimeout(c_, timeout);
-    mu_.ReaderUnlock();
-    return b;
-  }
+  // Should the absolute deadline API based on absl::Time be tested?  If false,
+  // the relative deadline API based on absl::Duration is tested.
+  bool use_absolute_deadline;
 
-  void Await() {
-    absl::MutexLock lock(&mu_);
-    mu_.Await(c_);
-  }
+  // The deadline/timeout used when calling the API being tested
+  // (e.g. Mutex::LockWhenWithDeadline).
+  absl::Duration wait_timeout;
 
-  void Signal(bool v) {
-    absl::MutexLock lock(&mu_);
-    b_ = v;
-    cv_.Signal();
-  }
+  // The delay before the condition will be set true by the test code.  If zero
+  // or negative, the condition is set true immediately (before calling the API
+  // being tested).  Otherwise, if infinite, the condition is never set true.
+  // Otherwise a closure is scheduled for the future that sets the condition
+  // true.
+  absl::Duration satisfy_condition_delay;
 
-  bool WaitWithTimeout(absl::Duration timeout) {
-    absl::MutexLock lock(&mu_);
-    absl::Time deadline = absl::Now() + timeout;
-    if (use_deadline_) {
-      while (!b_ && !cv_.WaitWithDeadline(&mu_, deadline)) {
-      }
-    } else {
-      while (!b_ && !cv_.WaitWithTimeout(&mu_, timeout)) {
-        timeout = deadline - absl::Now();  // recompute timeout
-      }
-    }
-    return b_;
-  }
+  // The expected result of the condition after the call to the API being
+  // tested. Generally `true` means the condition was true when the API returns,
+  // `false` indicates an expected timeout.
+  bool expected_result;
 
-  void Wait() {
-    absl::MutexLock lock(&mu_);
-    while (!b_) cv_.Wait(&mu_);
-  }
-
- private:
-  const bool use_deadline_;
-
-  bool b_;
-  absl::Condition c_;
-  absl::CondVar cv_;
-  absl::Mutex mu_;
+  // The expected delay before the API under test returns.  This is inherently
+  // flaky, so some slop is allowed (see `DelayIsWithinBounds` above), and the
+  // test keeps trying indefinitely until this constraint passes.
+  absl::Duration expected_delay;
 };
 
-class OperationTimer {
- public:
-  OperationTimer() : start_(absl::Now()) {}
-  absl::Duration Get() const { return absl::Now() - start_; }
+// Print a `TimeoutTestParam` to a debug log.
+std::ostream &operator<<(std::ostream &os, const TimeoutTestParam &param) {
+  return os << "from: " << param.from_file << ":" << param.from_line
+            << " use_absolute_deadline: "
+            << (param.use_absolute_deadline ? "true" : "false")
+            << " wait_timeout: " << param.wait_timeout
+            << " satisfy_condition_delay: " << param.satisfy_condition_delay
+            << " expected_result: "
+            << (param.expected_result ? "true" : "false")
+            << " expected_delay: " << param.expected_delay;
+}
 
- private:
-  const absl::Time start_;
-};
+std::string FormatString(const TimeoutTestParam &param) {
+  std::ostringstream os;
+  os << param;
+  return os.str();
+}
 
-static void CheckResults(bool exp_result, bool act_result,
-                         absl::Duration exp_duration,
-                         absl::Duration act_duration) {
-  ABSL_RAW_CHECK(exp_result == act_result, "CheckResults failed");
-  // Allow for some worse-case scheduling delay and clock skew.
-  if ((exp_duration - absl::Milliseconds(40) > act_duration) ||
-      (exp_duration + absl::Milliseconds(150) < act_duration)) {
-    ABSL_RAW_LOG(FATAL, "CheckResults failed: operation took %s, expected %s",
-                 absl::FormatDuration(act_duration).c_str(),
-                 absl::FormatDuration(exp_duration).c_str());
+// Like `thread::Executor::ScheduleAt` except:
+// a) Delays zero or negative are executed immediately in the current thread.
+// b) Infinite delays are never scheduled.
+// c) Calls this test's `ScheduleAt` helper instead of using `pool` directly.
+static void RunAfterDelay(absl::Duration delay,
+                          absl::synchronization_internal::ThreadPool *pool,
+                          const std::function<void()> &callback) {
+  if (delay <= absl::ZeroDuration()) {
+    callback();  // immediate
+  } else if (delay != absl::InfiniteDuration()) {
+    ScheduleAfter(pool, delay, callback);
   }
 }
 
-static void TestAwaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
-                             absl::Duration exp_duration) {
-  OperationTimer t;
-  bool act_result = cp->AwaitWithTimeout(timeout);
-  CheckResults(exp_result, act_result, exp_duration, t.Get());
-}
+class TimeoutTest : public ::testing::Test,
+                    public ::testing::WithParamInterface<TimeoutTestParam> {};
 
-static void TestLockWhenTimeout(Cond *cp, absl::Duration timeout,
-                                bool exp_result, absl::Duration exp_duration) {
-  OperationTimer t;
-  bool act_result = cp->LockWhenWithTimeout(timeout);
-  CheckResults(exp_result, act_result, exp_duration, t.Get());
-}
-
-static void TestReaderLockWhenTimeout(Cond *cp, absl::Duration timeout,
-                                      bool exp_result,
-                                      absl::Duration exp_duration) {
-  OperationTimer t;
-  bool act_result = cp->ReaderLockWhenWithTimeout(timeout);
-  CheckResults(exp_result, act_result, exp_duration, t.Get());
-}
-
-static void TestWaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
-                            absl::Duration exp_duration) {
-  OperationTimer t;
-  bool act_result = cp->WaitWithTimeout(timeout);
-  CheckResults(exp_result, act_result, exp_duration, t.Get());
-}
-
-// Tests with a negative timeout (deadline in the past), which should
-// immediately return the current state of the condition.
-static void TestNegativeTimeouts(absl::synchronization_internal::ThreadPool *tp,
-                                 Cond *cp) {
+std::vector<TimeoutTestParam> MakeTimeoutTestParamValues() {
+  // The `finite` delay is a finite, relatively short, delay.  We make it larger
+  // than our allowed scheduling delay (slop factor) to avoid confusion when
+  // diagnosing test failures.  The other constants here have clear meanings.
+  const absl::Duration finite = 3 * TimeoutTestAllowedSchedulingDelay();
+  const absl::Duration never = absl::InfiniteDuration();
   const absl::Duration negative = -absl::InfiniteDuration();
   const absl::Duration immediate = absl::ZeroDuration();
 
-  // The condition is already true:
-  cp->Set(true);
-  TestAwaitTimeout(cp, negative, true, immediate);
-  TestLockWhenTimeout(cp, negative, true, immediate);
-  TestReaderLockWhenTimeout(cp, negative, true, immediate);
-  TestWaitTimeout(cp, negative, true, immediate);
+  // Every test case is run twice; once using the absolute deadline API and once
+  // using the relative timeout API.
+  std::vector<TimeoutTestParam> values;
+  for (bool use_absolute_deadline : {false, true}) {
+    // Tests with a negative timeout (deadline in the past), which should
+    // immediately return current state of the condition.
 
-  // The condition becomes true, but the timeout has already expired:
-  const absl::Duration delay = absl::Milliseconds(200);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay);
-  TestAwaitTimeout(cp, negative, false, immediate);
-  TestLockWhenTimeout(cp, negative, false, immediate);
-  TestReaderLockWhenTimeout(cp, negative, false, immediate);
-  cp->Await();  // wait for the scheduled Set() to complete
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
-  TestWaitTimeout(cp, negative, false, immediate);
-  cp->Wait();  // wait for the scheduled Signal() to complete
+    // The condition is already true:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        negative,   // wait_timeout
+        immediate,  // satisfy_condition_delay
+        true,       // expected_result
+        immediate,  // expected_delay
+    });
 
-  // The condition never becomes true:
-  cp->Set(false);
-  TestAwaitTimeout(cp, negative, false, immediate);
-  TestLockWhenTimeout(cp, negative, false, immediate);
-  TestReaderLockWhenTimeout(cp, negative, false, immediate);
-  TestWaitTimeout(cp, negative, false, immediate);
+    // The condition becomes true, but the timeout has already expired:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        negative,  // wait_timeout
+        finite,    // satisfy_condition_delay
+        false,     // expected_result
+        immediate  // expected_delay
+    });
+
+    // The condition never becomes true:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        negative,  // wait_timeout
+        never,     // satisfy_condition_delay
+        false,     // expected_result
+        immediate  // expected_delay
+    });
+
+    // Tests with an infinite timeout (deadline in the infinite future), which
+    // should only return when the condition becomes true.
+
+    // The condition is already true:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        never,      // wait_timeout
+        immediate,  // satisfy_condition_delay
+        true,       // expected_result
+        immediate   // expected_delay
+    });
+
+    // The condition becomes true before the (infinite) expiry:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        never,   // wait_timeout
+        finite,  // satisfy_condition_delay
+        true,    // expected_result
+        finite,  // expected_delay
+    });
+
+    // Tests with a (small) finite timeout (deadline soon), with the condition
+    // becoming true both before and after its expiry.
+
+    // The condition is already true:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        never,      // wait_timeout
+        immediate,  // satisfy_condition_delay
+        true,       // expected_result
+        immediate   // expected_delay
+    });
+
+    // The condition becomes true before the expiry:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        finite * 2,  // wait_timeout
+        finite,      // satisfy_condition_delay
+        true,        // expected_result
+        finite       // expected_delay
+    });
+
+    // The condition becomes true, but the timeout has already expired:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        finite,      // wait_timeout
+        finite * 2,  // satisfy_condition_delay
+        false,       // expected_result
+        finite       // expected_delay
+    });
+
+    // The condition never becomes true:
+    values.push_back(TimeoutTestParam{
+        __FILE__, __LINE__, use_absolute_deadline,
+        finite,  // wait_timeout
+        never,   // satisfy_condition_delay
+        false,   // expected_result
+        finite   // expected_delay
+    });
+  }
+  return values;
 }
 
-// Tests with an infinite timeout (deadline in the infinite future), which
-// should only return when the condition becomes true.
-static void TestInfiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
-                                 Cond *cp) {
-  const absl::Duration infinite = absl::InfiniteDuration();
-  const absl::Duration immediate = absl::ZeroDuration();
+// Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`.
+INSTANTIATE_TEST_CASE_P(All, TimeoutTest,
+                        testing::ValuesIn(MakeTimeoutTestParamValues()));
 
-  // The condition is already true:
-  cp->Set(true);
-  TestAwaitTimeout(cp, infinite, true, immediate);
-  TestLockWhenTimeout(cp, infinite, true, immediate);
-  TestReaderLockWhenTimeout(cp, infinite, true, immediate);
-  TestWaitTimeout(cp, infinite, true, immediate);
+TEST_P(TimeoutTest, Await) {
+  const TimeoutTestParam params = GetParam();
+  ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
 
-  // The condition becomes true before the (infinite) expiry:
-  const absl::Duration delay = absl::Milliseconds(200);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
-  TestAwaitTimeout(cp, infinite, true, delay);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
-  TestLockWhenTimeout(cp, infinite, true, delay);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
-  TestReaderLockWhenTimeout(cp, infinite, true, delay);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
-  TestWaitTimeout(cp, infinite, true, delay);
+  // Because this test asserts bounds on scheduling delays it is flaky.  To
+  // compensate it loops forever until it passes.  Failures express as test
+  // timeouts, in which case the test log can be used to diagnose the issue.
+  for (int attempt = 1;; ++attempt) {
+    ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
+
+    absl::Mutex mu;
+    bool value = false;  // condition value (under mu)
+
+    std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
+        CreateDefaultPool();
+    RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
+      absl::MutexLock l(&mu);
+      value = true;
+    });
+
+    absl::MutexLock lock(&mu);
+    absl::Time start_time = absl::Now();
+    absl::Condition cond(&value);
+    bool result =
+        params.use_absolute_deadline
+            ? mu.AwaitWithDeadline(cond, start_time + params.wait_timeout)
+            : mu.AwaitWithTimeout(cond, params.wait_timeout);
+    if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
+      EXPECT_EQ(params.expected_result, result);
+      break;
+    }
+  }
 }
 
-// Tests with a (small) finite timeout (deadline soon), with the condition
-// becoming true both before and after its expiry.
-static void TestFiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
-                               Cond *cp) {
-  const absl::Duration finite = absl::Milliseconds(400);
-  const absl::Duration immediate = absl::ZeroDuration();
+TEST_P(TimeoutTest, LockWhen) {
+  const TimeoutTestParam params = GetParam();
+  ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
 
-  // The condition is already true:
-  cp->Set(true);
-  TestAwaitTimeout(cp, finite, true, immediate);
-  TestLockWhenTimeout(cp, finite, true, immediate);
-  TestReaderLockWhenTimeout(cp, finite, true, immediate);
-  TestWaitTimeout(cp, finite, true, immediate);
+  // Because this test asserts bounds on scheduling delays it is flaky.  To
+  // compensate it loops forever until it passes.  Failures express as test
+  // timeouts, in which case the test log can be used to diagnose the issue.
+  for (int attempt = 1;; ++attempt) {
+    ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
 
-  // The condition becomes true before the expiry:
-  const absl::Duration delay1 = finite / 2;
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
-  TestAwaitTimeout(cp, finite, true, delay1);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
-  TestLockWhenTimeout(cp, finite, true, delay1);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
-  TestReaderLockWhenTimeout(cp, finite, true, delay1);
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay1);
-  TestWaitTimeout(cp, finite, true, delay1);
+    absl::Mutex mu;
+    bool value = false;  // condition value (under mu)
 
-  // The condition becomes true, but the timeout has already expired:
-  const absl::Duration delay2 = finite * 2;
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay2);
-  TestAwaitTimeout(cp, finite, false, finite);
-  TestLockWhenTimeout(cp, finite, false, finite);
-  TestReaderLockWhenTimeout(cp, finite, false, finite);
-  cp->Await();  // wait for the scheduled Set() to complete
-  cp->Set(false);
-  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay2);
-  TestWaitTimeout(cp, finite, false, finite);
-  cp->Wait();  // wait for the scheduled Signal() to complete
+    std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
+        CreateDefaultPool();
+    RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
+      absl::MutexLock l(&mu);
+      value = true;
+    });
 
-  // The condition never becomes true:
-  cp->Set(false);
-  TestAwaitTimeout(cp, finite, false, finite);
-  TestLockWhenTimeout(cp, finite, false, finite);
-  TestReaderLockWhenTimeout(cp, finite, false, finite);
-  TestWaitTimeout(cp, finite, false, finite);
+    absl::Time start_time = absl::Now();
+    absl::Condition cond(&value);
+    bool result =
+        params.use_absolute_deadline
+            ? mu.LockWhenWithDeadline(cond, start_time + params.wait_timeout)
+            : mu.LockWhenWithTimeout(cond, params.wait_timeout);
+    mu.Unlock();
+
+    if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
+      EXPECT_EQ(params.expected_result, result);
+      break;
+    }
+  }
 }
 
-TEST(Mutex, Timeouts) {
-  auto tp = CreateDefaultPool();
-  for (bool use_deadline : {false, true}) {
-    Cond cond(use_deadline);
-    TestNegativeTimeouts(tp.get(), &cond);
-    TestInfiniteTimeouts(tp.get(), &cond);
-    TestFiniteTimeouts(tp.get(), &cond);
+TEST_P(TimeoutTest, ReaderLockWhen) {
+  const TimeoutTestParam params = GetParam();
+  ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
+
+  // Because this test asserts bounds on scheduling delays it is flaky.  To
+  // compensate it loops forever until it passes.  Failures express as test
+  // timeouts, in which case the test log can be used to diagnose the issue.
+  for (int attempt = 0;; ++attempt) {
+    ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
+
+    absl::Mutex mu;
+    bool value = false;  // condition value (under mu)
+
+    std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
+        CreateDefaultPool();
+    RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
+      absl::MutexLock l(&mu);
+      value = true;
+    });
+
+    absl::Time start_time = absl::Now();
+    bool result =
+        params.use_absolute_deadline
+            ? mu.ReaderLockWhenWithDeadline(absl::Condition(&value),
+                                            start_time + params.wait_timeout)
+            : mu.ReaderLockWhenWithTimeout(absl::Condition(&value),
+                                           params.wait_timeout);
+    mu.ReaderUnlock();
+
+    if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
+      EXPECT_EQ(params.expected_result, result);
+      break;
+    }
+  }
+}
+
+TEST_P(TimeoutTest, Wait) {
+  const TimeoutTestParam params = GetParam();
+  ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
+
+  // Because this test asserts bounds on scheduling delays it is flaky.  To
+  // compensate it loops forever until it passes.  Failures express as test
+  // timeouts, in which case the test log can be used to diagnose the issue.
+  for (int attempt = 0;; ++attempt) {
+    ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
+
+    absl::Mutex mu;
+    bool value = false;  // condition value (under mu)
+    absl::CondVar cv;    // signals a change of `value`
+
+    std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
+        CreateDefaultPool();
+    RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
+      absl::MutexLock l(&mu);
+      value = true;
+      cv.Signal();
+    });
+
+    absl::MutexLock lock(&mu);
+    absl::Time start_time = absl::Now();
+    absl::Duration timeout = params.wait_timeout;
+    absl::Time deadline = start_time + timeout;
+    while (!value) {
+      if (params.use_absolute_deadline ? cv.WaitWithDeadline(&mu, deadline)
+                                       : cv.WaitWithTimeout(&mu, timeout)) {
+        break;  // deadline/timeout exceeded
+      }
+      timeout = deadline - absl::Now();  // recompute
+    }
+    bool result = value;  // note: `mu` is still held
+
+    if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
+      EXPECT_EQ(params.expected_result, result);
+      break;
+    }
   }
 }
 
diff --git a/third_party/abseil-cpp/absl/time/BUILD.bazel b/third_party/abseil-cpp/absl/time/BUILD.bazel
index e793da8..c7c16d4 100644
--- a/third_party/abseil-cpp/absl/time/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/time/BUILD.bazel
@@ -30,9 +30,8 @@
         "clock.cc",
         "duration.cc",
         "format.cc",
-        "internal/get_current_time_ios.inc",
+        "internal/get_current_time_chrono.inc",
         "internal/get_current_time_posix.inc",
-        "internal/get_current_time_windows.inc",
         "time.cc",
     ],
     hdrs = [
diff --git a/third_party/abseil-cpp/absl/time/BUILD.gn b/third_party/abseil-cpp/absl/time/BUILD.gn
index 24de31c..9927af8 100644
--- a/third_party/abseil-cpp/absl/time/BUILD.gn
+++ b/third_party/abseil-cpp/absl/time/BUILD.gn
@@ -14,30 +14,19 @@
   visibility = [ "*" ]
 }
 
-config("suppress_unguarded_availability") {
-  # TODO(bugs.webrtc.org/9557): Remove -Wno-unguarded-availability when
-  # abseil will support Xcode 9.0+ (it currently supports Xcode 7.3.1+
-  # which doesn't have -Wunguarded-availability and __builtin_available).
-  cflags = [
-    "-Wno-unguarded-availability",
-  ]
-}
-
 source_set("time") {
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [
     "//build/config/compiler:no_chromium_code",
     "//third_party/abseil-cpp:absl_default_cflags_cc",
-    ":suppress_unguarded_availability",
   ]
   public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
   sources = [
     "clock.cc",
     "duration.cc",
     "format.cc",
-    "internal/get_current_time_ios.inc",
+    "internal/get_current_time_chrono.inc",
     "internal/get_current_time_posix.inc",
-    "internal/get_current_time_windows.inc",
     "time.cc",
   ]
   public = [
diff --git a/third_party/abseil-cpp/absl/time/clock.cc b/third_party/abseil-cpp/absl/time/clock.cc
index 772f852..74ee140 100644
--- a/third_party/abseil-cpp/absl/time/clock.cc
+++ b/third_party/abseil-cpp/absl/time/clock.cc
@@ -57,10 +57,8 @@
 #endif
 #endif
 
-#if defined(__APPLE__)
-#include "absl/time/internal/get_current_time_ios.inc"
-#elif defined(_WIN32)
-#include "absl/time/internal/get_current_time_windows.inc"
+#if defined(__APPLE__) || defined(_WIN32)
+#include "absl/time/internal/get_current_time_chrono.inc"
 #else
 #include "absl/time/internal/get_current_time_posix.inc"
 #endif
diff --git a/third_party/abseil-cpp/absl/time/clock_test.cc b/third_party/abseil-cpp/absl/time/clock_test.cc
index f143c036..707166d 100644
--- a/third_party/abseil-cpp/absl/time/clock_test.cc
+++ b/third_party/abseil-cpp/absl/time/clock_test.cc
@@ -35,36 +35,84 @@
   EXPECT_GE(after, now);
 }
 
-TEST(SleepForTest, BasicSanity) {
-  absl::Duration sleep_time = absl::Milliseconds(2500);
-  absl::Time start = absl::Now();
-  absl::SleepFor(sleep_time);
-  absl::Time end = absl::Now();
-  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
-  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
-}
+enum class AlarmPolicy { kWithoutAlarm, kWithAlarm };
 
-#ifdef ABSL_HAVE_ALARM
-// Helper for test SleepFor.
+#if defined(ABSL_HAVE_ALARM)
 bool alarm_handler_invoked = false;
+
 void AlarmHandler(int signo) {
   ASSERT_EQ(signo, SIGALRM);
   alarm_handler_invoked = true;
 }
+#endif
 
-TEST(SleepForTest, AlarmSupport) {
-  alarm_handler_invoked = false;
-  sig_t old_alarm = signal(SIGALRM, AlarmHandler);
-  alarm(2);
-  absl::Duration sleep_time = absl::Milliseconds(3500);
-  absl::Time start = absl::Now();
-  absl::SleepFor(sleep_time);
-  absl::Time end = absl::Now();
-  EXPECT_TRUE(alarm_handler_invoked);
-  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
-  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
-  signal(SIGALRM, old_alarm);
+// Does SleepFor(d) take between lower_bound and upper_bound at least
+// once between now and (now + timeout)?  If requested (and supported),
+// add an alarm for the middle of the sleep period and expect it to fire.
+bool SleepForBounded(absl::Duration d, absl::Duration lower_bound,
+                     absl::Duration upper_bound, absl::Duration timeout,
+                     AlarmPolicy alarm_policy, int* attempts) {
+  const absl::Time deadline = absl::Now() + timeout;
+  while (absl::Now() < deadline) {
+#if defined(ABSL_HAVE_ALARM)
+    sig_t old_alarm = SIG_DFL;
+    if (alarm_policy == AlarmPolicy::kWithAlarm) {
+      alarm_handler_invoked = false;
+      old_alarm = signal(SIGALRM, AlarmHandler);
+      alarm(absl::ToInt64Seconds(d / 2));
+    }
+#else
+    EXPECT_EQ(alarm_policy, AlarmPolicy::kWithoutAlarm);
+#endif
+    ++*attempts;
+    absl::Time start = absl::Now();
+    absl::SleepFor(d);
+    absl::Duration actual = absl::Now() - start;
+#if defined(ABSL_HAVE_ALARM)
+    if (alarm_policy == AlarmPolicy::kWithAlarm) {
+      signal(SIGALRM, old_alarm);
+      if (!alarm_handler_invoked) continue;
+    }
+#endif
+    if (lower_bound <= actual && actual <= upper_bound) {
+      return true;  // yes, the SleepFor() was correctly bounded
+    }
+  }
+  return false;
 }
-#endif  // ABSL_HAVE_ALARM
+
+testing::AssertionResult AssertSleepForBounded(absl::Duration d,
+                                               absl::Duration early,
+                                               absl::Duration late,
+                                               absl::Duration timeout,
+                                               AlarmPolicy alarm_policy) {
+  const absl::Duration lower_bound = d - early;
+  const absl::Duration upper_bound = d + late;
+  int attempts = 0;
+  if (SleepForBounded(d, lower_bound, upper_bound, timeout, alarm_policy,
+                      &attempts)) {
+    return testing::AssertionSuccess();
+  }
+  return testing::AssertionFailure()
+         << "SleepFor(" << d << ") did not return within [" << lower_bound
+         << ":" << upper_bound << "] in " << attempts << " attempt"
+         << (attempts == 1 ? "" : "s") << " over " << timeout
+         << (alarm_policy == AlarmPolicy::kWithAlarm ? " with" : " without")
+         << " an alarm";
+}
+
+// Tests that SleepFor() returns neither too early nor too late.
+TEST(SleepFor, Bounded) {
+  const absl::Duration d = absl::Milliseconds(2500);
+  const absl::Duration early = absl::Milliseconds(100);
+  const absl::Duration late = absl::Milliseconds(300);
+  const absl::Duration timeout = 48 * d;
+  EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
+                                    AlarmPolicy::kWithoutAlarm));
+#if defined(ABSL_HAVE_ALARM)
+  EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
+                                    AlarmPolicy::kWithAlarm));
+#endif
+}
 
 }  // namespace
diff --git a/third_party/abseil-cpp/absl/time/duration.cc b/third_party/abseil-cpp/absl/time/duration.cc
index c13fa79..f402137b 100644
--- a/third_party/abseil-cpp/absl/time/duration.cc
+++ b/third_party/abseil-cpp/absl/time/duration.cc
@@ -895,13 +895,10 @@
   *d = dur;
   return true;
 }
-
 bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
   return ParseDuration(text, dst);
 }
 
-std::string UnparseFlag(Duration d) {
-  return FormatDuration(d);
-}
+std::string UnparseFlag(Duration d) { return FormatDuration(d); }
 
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/time/duration_benchmark.cc b/third_party/abseil-cpp/absl/time/duration_benchmark.cc
index 54f89a1..d5657bd 100644
--- a/third_party/abseil-cpp/absl/time/duration_benchmark.cc
+++ b/third_party/abseil-cpp/absl/time/duration_benchmark.cc
@@ -27,47 +27,113 @@
 //
 
 void BM_Duration_Factory_Nanoseconds(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Nanoseconds(1));
+    benchmark::DoNotOptimize(absl::Nanoseconds(i));
+    i += 314159;
   }
 }
 BENCHMARK(BM_Duration_Factory_Nanoseconds);
 
 void BM_Duration_Factory_Microseconds(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Microseconds(1));
+    benchmark::DoNotOptimize(absl::Microseconds(i));
+    i += 314;
   }
 }
 BENCHMARK(BM_Duration_Factory_Microseconds);
 
 void BM_Duration_Factory_Milliseconds(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Milliseconds(1));
+    benchmark::DoNotOptimize(absl::Milliseconds(i));
+    i += 1;
   }
 }
 BENCHMARK(BM_Duration_Factory_Milliseconds);
 
 void BM_Duration_Factory_Seconds(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Seconds(1));
+    benchmark::DoNotOptimize(absl::Seconds(i));
+    i += 1;
   }
 }
 BENCHMARK(BM_Duration_Factory_Seconds);
 
 void BM_Duration_Factory_Minutes(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Minutes(1));
+    benchmark::DoNotOptimize(absl::Minutes(i));
+    i += 1;
   }
 }
 BENCHMARK(BM_Duration_Factory_Minutes);
 
 void BM_Duration_Factory_Hours(benchmark::State& state) {
+  int64_t i = 0;
   while (state.KeepRunning()) {
-    benchmark::DoNotOptimize(absl::Hours(1));
+    benchmark::DoNotOptimize(absl::Hours(i));
+    i += 1;
   }
 }
 BENCHMARK(BM_Duration_Factory_Hours);
 
+void BM_Duration_Factory_DoubleNanoseconds(benchmark::State& state) {
+  double d = 1;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Nanoseconds(d));
+    d = d * 1.00000001 + 1;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleNanoseconds);
+
+void BM_Duration_Factory_DoubleMicroseconds(benchmark::State& state) {
+  double d = 1e-3;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Microseconds(d));
+    d = d * 1.00000001 + 1e-3;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleMicroseconds);
+
+void BM_Duration_Factory_DoubleMilliseconds(benchmark::State& state) {
+  double d = 1e-6;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Milliseconds(d));
+    d = d * 1.00000001 + 1e-6;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleMilliseconds);
+
+void BM_Duration_Factory_DoubleSeconds(benchmark::State& state) {
+  double d = 1e-9;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Seconds(d));
+    d = d * 1.00000001 + 1e-9;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleSeconds);
+
+void BM_Duration_Factory_DoubleMinutes(benchmark::State& state) {
+  double d = 1e-9;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Minutes(d));
+    d = d * 1.00000001 + 1e-9;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleMinutes);
+
+void BM_Duration_Factory_DoubleHours(benchmark::State& state) {
+  double d = 1e-9;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Hours(d));
+    d = d * 1.00000001 + 1e-9;
+  }
+}
+BENCHMARK(BM_Duration_Factory_DoubleHours);
+
 //
 // Arithmetic
 //
diff --git a/third_party/abseil-cpp/absl/time/duration_test.cc b/third_party/abseil-cpp/absl/time/duration_test.cc
index 704684e..7ae25dc6 100644
--- a/third_party/abseil-cpp/absl/time/duration_test.cc
+++ b/third_party/abseil-cpp/absl/time/duration_test.cc
@@ -16,7 +16,9 @@
 #include <cmath>
 #include <cstdint>
 #include <ctime>
+#include <iomanip>
 #include <limits>
+#include <random>
 #include <string>
 
 #include "gmock/gmock.h"
@@ -105,22 +107,22 @@
 }
 
 TEST(Duration, ToConversion) {
-#define TEST_DURATION_CONVERSION(UNIT)                              \
-  do {                                                              \
-    const absl::Duration d = absl::UNIT(1.5);                       \
-    const absl::Duration z = absl::ZeroDuration();                  \
-    const absl::Duration inf = absl::InfiniteDuration();            \
-    const double dbl_inf = std::numeric_limits<double>::infinity(); \
-    EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf));                \
-    EXPECT_EQ(-1, absl::ToInt64##UNIT(-d));                         \
-    EXPECT_EQ(0, absl::ToInt64##UNIT(z));                           \
-    EXPECT_EQ(1, absl::ToInt64##UNIT(d));                           \
-    EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf));                 \
-    EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf));                \
-    EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d));                      \
-    EXPECT_EQ(0, absl::ToDouble##UNIT(z));                          \
-    EXPECT_EQ(1.5, absl::ToDouble##UNIT(d));                        \
-    EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf));                  \
+#define TEST_DURATION_CONVERSION(UNIT)                                  \
+  do {                                                                  \
+    const absl::Duration d = absl::UNIT(1.5);                           \
+    constexpr absl::Duration z = absl::ZeroDuration();                  \
+    constexpr absl::Duration inf = absl::InfiniteDuration();            \
+    constexpr double dbl_inf = std::numeric_limits<double>::infinity(); \
+    EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf));                    \
+    EXPECT_EQ(-1, absl::ToInt64##UNIT(-d));                             \
+    EXPECT_EQ(0, absl::ToInt64##UNIT(z));                               \
+    EXPECT_EQ(1, absl::ToInt64##UNIT(d));                               \
+    EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf));                     \
+    EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf));                    \
+    EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d));                          \
+    EXPECT_EQ(0, absl::ToDouble##UNIT(z));                              \
+    EXPECT_EQ(1.5, absl::ToDouble##UNIT(d));                            \
+    EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf));                      \
   } while (0)
 
   TEST_DURATION_CONVERSION(Nanoseconds);
@@ -1284,6 +1286,16 @@
   EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(0.875e-9));
   EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(1.000e-9));
 
+  EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(-0.124999999e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.125e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.250e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.375e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.500e-9));
+  EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.625e-9));
+  EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.750e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-0.875e-9));
+  EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-1.000e-9));
+
   timespec ts;
   ts.tv_sec = 0;
   ts.tv_nsec = 0;
@@ -1313,6 +1325,86 @@
   EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv));
 }
 
+void VerifySameAsMul(double time_as_seconds, int* const misses) {
+  auto direct_seconds = absl::Seconds(time_as_seconds);
+  auto mul_by_one_second = time_as_seconds * absl::Seconds(1);
+  if (direct_seconds != mul_by_one_second) {
+    if (*misses > 10) return;
+    ASSERT_LE(++(*misses), 10) << "Too many errors, not reporting more.";
+    EXPECT_EQ(direct_seconds, mul_by_one_second)
+        << "given double time_as_seconds = " << std::setprecision(17)
+        << time_as_seconds;
+  }
+}
+
+// For a variety of interesting durations, we find the exact point
+// where one double converts to that duration, and the very next double
+// converts to the next duration.  For both of those points, verify that
+// Seconds(point) returns the same duration as point * Seconds(1.0)
+TEST(Duration, ToDoubleSecondsCheckEdgeCases) {
+  constexpr uint32_t kTicksPerSecond = absl::time_internal::kTicksPerSecond;
+  constexpr auto duration_tick = absl::time_internal::MakeDuration(0, 1u);
+  int misses = 0;
+  for (int64_t seconds = 0; seconds < 99; ++seconds) {
+    uint32_t tick_vals[] = {0, +999, +999999, +999999999, kTicksPerSecond - 1,
+                            0, 1000, 1000000, 1000000000, kTicksPerSecond,
+                            1, 1001, 1000001, 1000000001, kTicksPerSecond + 1,
+                            2, 1002, 1000002, 1000000002, kTicksPerSecond + 2,
+                            3, 1003, 1000003, 1000000003, kTicksPerSecond + 3,
+                            4, 1004, 1000004, 1000000004, kTicksPerSecond + 4,
+                            5, 6,    7,       8,          9};
+    for (uint32_t ticks : tick_vals) {
+      absl::Duration s_plus_t = absl::Seconds(seconds) + ticks * duration_tick;
+      for (absl::Duration d : {s_plus_t, -s_plus_t}) {
+        absl::Duration after_d = d + duration_tick;
+        EXPECT_NE(d, after_d);
+        EXPECT_EQ(after_d - d, duration_tick);
+
+        double low_edge = ToDoubleSeconds(d);
+        EXPECT_EQ(d, absl::Seconds(low_edge));
+
+        double high_edge = ToDoubleSeconds(after_d);
+        EXPECT_EQ(after_d, absl::Seconds(high_edge));
+
+        for (;;) {
+          double midpoint = low_edge + (high_edge - low_edge) / 2;
+          if (midpoint == low_edge || midpoint == high_edge) break;
+          absl::Duration mid_duration = absl::Seconds(midpoint);
+          if (mid_duration == d) {
+            low_edge = midpoint;
+          } else {
+            EXPECT_EQ(mid_duration, after_d);
+            high_edge = midpoint;
+          }
+        }
+        // Now low_edge is the highest double that converts to Duration d,
+        // and high_edge is the lowest double that converts to Duration after_d.
+        VerifySameAsMul(low_edge, &misses);
+        VerifySameAsMul(high_edge, &misses);
+      }
+    }
+  }
+}
+
+TEST(Duration, ToDoubleSecondsCheckRandom) {
+  std::random_device rd;
+  std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()});
+  std::mt19937_64 gen(seed);
+  // We want doubles distributed from 1/8ns up to 2^63, where
+  // as many values are tested from 1ns to 2ns as from 1sec to 2sec,
+  // so even distribute along a log-scale of those values, and
+  // exponentiate before using them.  (9.223377e+18 is just slightly
+  // out of bounds for absl::Duration.)
+  std::uniform_real_distribution<double> uniform(std::log(0.125e-9),
+                                                 std::log(9.223377e+18));
+  int misses = 0;
+  for (int i = 0; i < 1000000; ++i) {
+    double d = std::exp(uniform(gen));
+    VerifySameAsMul(d, &misses);
+    VerifySameAsMul(-d, &misses);
+  }
+}
+
 TEST(Duration, ConversionSaturation) {
   absl::Duration d;
 
diff --git a/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc b/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc
new file mode 100644
index 0000000..cf884a1
--- /dev/null
+++ b/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <chrono>
+#include <cstdint>
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::system_clock::now() -
+             std::chrono::system_clock::from_time_t(0))
+      .count();
+}
+
+}  // namespace time_internal
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/time/internal/get_current_time_ios.inc b/third_party/abseil-cpp/absl/time/internal/get_current_time_ios.inc
deleted file mode 100644
index f3db32b..0000000
--- a/third_party/abseil-cpp/absl/time/internal/get_current_time_ios.inc
+++ /dev/null
@@ -1,80 +0,0 @@
-#include "absl/time/clock.h"
-
-#include <sys/time.h>
-#include <ctime>
-#include <cstdint>
-
-#include "absl/base/internal/raw_logging.h"
-
-// These are not defined in the Xcode 7.3.1 SDK Headers.
-// Once we are no longer supporting Xcode 7.3.1 we can
-// remove these.
-#ifndef __WATCHOS_3_0
-#define __WATCHOS_3_0 30000
-#endif
-
-#ifndef __TVOS_10_0
-#define __TVOS_10_0 100000
-#endif
-
-#ifndef __IPHONE_10_0
-#define __IPHONE_10_0 100000
-#endif
-
-#ifndef __MAC_10_12
-#define __MAC_10_12 101200
-#endif
-
-namespace absl {
-namespace time_internal {
-
-static int64_t GetCurrentTimeNanosFromSystem() {
-#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12) ||    \
-    (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0) || \
-    (__WATCH_OS_VERSION_MAX_ALLOWED >= __WATCHOS_3_0) ||  \
-    (__TV_OS_VERSION_MAX_ALLOWED >= __TVOS_10_0)
-  // clock_gettime_nsec_np is not defined on SDKs before Xcode 8.0.
-  // This preprocessor logic is based upon __CLOCK_AVAILABILITY in
-  // usr/include/time.h. Once we are no longer supporting Xcode 7.3.1 we can
-  // remove this #if.
-  // We must continue to check if it is defined until we are sure that ALL the
-  // platforms we are shipping on support it.
-  // clock_gettime_nsec_np is preferred because it may give higher accuracy than
-  // gettimeofday in future Apple operating systems.
-  // Currently (macOS 10.12/iOS 10.2) clock_gettime_nsec_np accuracy is
-  // microsecond accuracy (i.e. equivalent to gettimeofday).
-  if (&clock_gettime_nsec_np != nullptr) {
-    return clock_gettime_nsec_np(CLOCK_REALTIME);
-  }
-#endif
-#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) &&            \
-     (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12)) ||    \
-    (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) &&           \
-     (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)) || \
-    (defined(__WATCH_OS_VERSION_MIN_REQUIRED) &&            \
-     (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_3_0)) ||  \
-    (defined(__TV_OS_VERSION_MIN_REQUIRED) &&               \
-     (__TV_OS_VERSION_MIN_REQUIRED < __TVOS_10_0))
-  // We need this block in 2 different cases:
-  // a) where we are compiling with Xcode 7 in which case the block above
-  //    will not be compiled in, and this is the only block executed.
-  // b) where we are compiling with Xcode 8+ but supporting operating systems
-  //    that do not define clock_gettime_nsec_np, so this is in effect
-  //    an else block to the block above.
-  // This block will not be compiled if the min supported version is
-  // guaranteed to supply clock_gettime_nsec_np.
-  //
-  // Once we know that clock_gettime_nsec_np is in the SDK *AND* exists on
-  // all the platforms we support, we can remove both this block and alter the
-  // block above to just call clock_gettime_nsec_np directly.
-  const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
-  const int64_t kNanosPerMicrosecond = 1000;
-  struct timeval tp;
-  ABSL_RAW_CHECK(gettimeofday(&tp, nullptr) == 0, "Failed gettimeofday");
-  return (int64_t{tp.tv_sec} * kNanosPerSecond +
-          int64_t{tp.tv_usec} * kNanosPerMicrosecond);
-#endif
-}
-
-}  // namespace time_internal
-}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/time/internal/get_current_time_windows.inc b/third_party/abseil-cpp/absl/time/internal/get_current_time_windows.inc
deleted file mode 100644
index b22a9c9..0000000
--- a/third_party/abseil-cpp/absl/time/internal/get_current_time_windows.inc
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "absl/time/clock.h"
-
-#include <chrono>
-#include <cstdint>
-
-namespace absl {
-namespace time_internal {
-
-static int64_t GetCurrentTimeNanosFromSystem() {
-  return std::chrono::duration_cast<std::chrono::nanoseconds>(
-             std::chrono::system_clock::now() -
-             std::chrono::system_clock::from_time_t(0))
-      .count();
-}
-
-}  // namespace time_internal
-}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/time/time.h b/third_party/abseil-cpp/absl/time/time.h
index ceec2de..c41cb89 100644
--- a/third_party/abseil-cpp/absl/time/time.h
+++ b/third_party/abseil-cpp/absl/time/time.h
@@ -50,7 +50,7 @@
 #ifndef ABSL_TIME_TIME_H_
 #define ABSL_TIME_TIME_H_
 
-#if !defined(_WIN32)
+#if !defined(_MSC_VER)
 #include <sys/time.h>
 #else
 #include <winsock2.h>
@@ -81,6 +81,7 @@
 constexpr uint32_t GetRepLo(Duration d);
 constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
 constexpr Duration MakeDuration(int64_t hi, int64_t lo);
+inline Duration MakePosDoubleDuration(double n);
 constexpr int64_t kTicksPerNanosecond = 4;
 constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
 template <std::intmax_t N>
@@ -295,6 +296,39 @@
 //   absl::Duration c = absl::Ceil(d, absl::Microseconds(1));   // 123457us
 Duration Ceil(Duration d, Duration unit);
 
+// InfiniteDuration()
+//
+// Returns an infinite `Duration`.  To get a `Duration` representing negative
+// infinity, use `-InfiniteDuration()`.
+//
+// Duration arithmetic overflows to +/- infinity and saturates. In general,
+// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
+// except where IEEE 754 NaN would be involved, in which case +/-
+// `InfiniteDuration()` is used in place of a "nan" Duration.
+//
+// Examples:
+//
+//   constexpr absl::Duration inf = absl::InfiniteDuration();
+//   const absl::Duration d = ... any finite duration ...
+//
+//   inf == inf + inf
+//   inf == inf + d
+//   inf == inf - inf
+//   -inf == d - inf
+//
+//   inf == d * 1e100
+//   inf == inf / 2
+//   0 == d / inf
+//   INT64_MAX == inf / d
+//
+//   // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
+//   inf == d / 0
+//   INT64_MAX == d / absl::ZeroDuration()
+//
+// The examples involving the `/` operator above also apply to `IDivDuration()`
+// and `FDivDuration()`.
+constexpr Duration InfiniteDuration();
+
 // Nanoseconds()
 // Microseconds()
 // Milliseconds()
@@ -344,7 +378,13 @@
 }
 template <typename T, time_internal::EnableIfFloat<T> = 0>
 Duration Seconds(T n) {
-  return n * Seconds(1);
+  if (n >= 0) {
+    if (n >= std::numeric_limits<int64_t>::max()) return InfiniteDuration();
+    return time_internal::MakePosDoubleDuration(n);
+  } else {
+    if (n <= std::numeric_limits<int64_t>::min()) return -InfiniteDuration();
+    return -time_internal::MakePosDoubleDuration(-n);
+  }
 }
 template <typename T, time_internal::EnableIfFloat<T> = 0>
 Duration Minutes(T n) {
@@ -439,39 +479,6 @@
 std::chrono::minutes ToChronoMinutes(Duration d);
 std::chrono::hours ToChronoHours(Duration d);
 
-// InfiniteDuration()
-//
-// Returns an infinite `Duration`.  To get a `Duration` representing negative
-// infinity, use `-InfiniteDuration()`.
-//
-// Duration arithmetic overflows to +/- infinity and saturates. In general,
-// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
-// except where IEEE 754 NaN would be involved, in which case +/-
-// `InfiniteDuration()` is used in place of a "nan" Duration.
-//
-// Examples:
-//
-//   constexpr absl::Duration inf = absl::InfiniteDuration();
-//   const absl::Duration d = ... any finite duration ...
-//
-//   inf == inf + inf
-//   inf == inf + d
-//   inf == inf - inf
-//   -inf == d - inf
-//
-//   inf == d * 1e100
-//   inf == inf / 2
-//   0 == d / inf
-//   INT64_MAX == inf / d
-//
-//   // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
-//   inf == d / 0
-//   INT64_MAX == d / absl::ZeroDuration()
-//
-// The examples involving the `/` operator above also apply to `IDivDuration()`
-// and `FDivDuration()`.
-constexpr Duration InfiniteDuration();
-
 // FormatDuration()
 //
 // Returns a std::string representing the duration in the form "72h3m0.5s".
@@ -492,12 +499,9 @@
 // `ZeroDuration()`.  Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
 bool ParseDuration(const std::string& dur_string, Duration* d);
 
-// ParseFlag()
-//
+// Support for flag values of type Duration. Duration flags must be specified
+// in a format that is valid input for absl::ParseDuration().
 bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
-
-// UnparseFlag()
-//
 std::string UnparseFlag(Duration d);
 
 // Time
@@ -991,9 +995,6 @@
 bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
                Time* time, std::string* err);
 
-// ParseFlag()
-// UnparseFlag()
-//
 // Support for flag values of type Time. Time flags must be specified in a
 // format that matches absl::RFC3339_full. For example:
 //
@@ -1114,6 +1115,18 @@
   return MakeDuration(hi, static_cast<uint32_t>(lo));
 }
 
+// Make a Duration value from a floating-point number, as long as that number
+// is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as
+// it's positive and can be converted to int64_t without risk of UB.
+inline Duration MakePosDoubleDuration(double n) {
+  const int64_t int_secs = static_cast<int64_t>(n);
+  const uint32_t ticks =
+      static_cast<uint32_t>((n - int_secs) * kTicksPerSecond + 0.5);
+  return ticks < kTicksPerSecond
+             ? MakeDuration(int_secs, ticks)
+             : MakeDuration(int_secs + 1, ticks - kTicksPerSecond);
+}
+
 // Creates a normalized Duration from an almost-normalized (sec,ticks)
 // pair. sec may be positive or negative.  ticks must be in the range
 // -kTicksPerSecond < *ticks < kTicksPerSecond.  If ticks is negative it
diff --git a/third_party/abseil-cpp/absl/types/internal/variant.h b/third_party/abseil-cpp/absl/types/internal/variant.h
index 7db5e05..7708e67 100644
--- a/third_party/abseil-cpp/absl/types/internal/variant.h
+++ b/third_party/abseil-cpp/absl/types/internal/variant.h
@@ -1062,32 +1062,6 @@
   static void Overload(...);
 };
 
-////////////////////////////////
-// Library Fundamentals V2 TS //
-////////////////////////////////
-
-// TODO(calabrese): Consider moving this to absl/meta/type_traits.h
-
-// The following is a rough implementation of parts of the detection idiom.
-// It is used for the comparison operator checks.
-
-template <class Enabler, class To, template <class...> class Op, class... Args>
-struct is_detected_convertible_impl {
-  using type = std::false_type;
-};
-
-template <class To, template <class...> class Op, class... Args>
-struct is_detected_convertible_impl<
-    absl::enable_if_t<std::is_convertible<Op<Args...>, To>::value>, To, Op,
-    Args...> {
-  using type = std::true_type;
-};
-
-// NOTE: This differs from library fundamentals by being lazy.
-template <class To, template <class...> class Op, class... Args>
-struct is_detected_convertible
-    : is_detected_convertible_impl<void, To, Op, Args...>::type {};
-
 template <class T>
 using LessThanResult = decltype(std::declval<T>() < std::declval<T>());
 
@@ -1107,6 +1081,8 @@
 template <class T>
 using NotEqualResult = decltype(std::declval<T>() != std::declval<T>());
 
+using type_traits_internal::is_detected_convertible;
+
 template <class... T>
 using RequireAllHaveEqualT = absl::enable_if_t<
     absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value,
diff --git a/third_party/abseil-cpp/absl/types/span_test.cc b/third_party/abseil-cpp/absl/types/span_test.cc
index 5a4f0014..fbce7e87 100644
--- a/third_party/abseil-cpp/absl/types/span_test.cc
+++ b/third_party/abseil-cpp/absl/types/span_test.cc
@@ -288,7 +288,7 @@
 #ifdef ABSL_HAVE_EXCEPTIONS
   EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range);
 #else
-  EXPECT_DEATH(absl::MakeSpan(ramp).subspan(11, 5), "");
+  EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).subspan(11, 5), "");
 #endif
 }
 
diff --git a/third_party/abseil-cpp/absl/types/variant.h b/third_party/abseil-cpp/absl/types/variant.h
index fd1d49ac..17e0634 100644
--- a/third_party/abseil-cpp/absl/types/variant.h
+++ b/third_party/abseil-cpp/absl/types/variant.h
@@ -248,7 +248,7 @@
 //
 // Example:
 //
-//   absl::variant<int, std::string> bar = 42;
+//   absl::variant<int, std::string> foo = 42;
 //   if (absl::holds_alternative<int>(foo)) {
 //       std::cout << "The variant holds an integer";
 //   }
@@ -449,14 +449,19 @@
 //------------------------------------------------------------------------------
 template <typename T0, typename... Tn>
 class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
+  static_assert(absl::conjunction<std::is_object<T0>,
+                                  std::is_object<Tn>...>::value,
+                "Attempted to instantiate a variant containing a non-object "
+                "type.");
   // Intentionally not qualifing `negation` with `absl::` to work around a bug
   // in MSVC 2015 with inline namespace and variadic template.
-  static_assert(absl::conjunction<std::is_object<T0>, std::is_object<Tn>...,
-                                  negation<std::is_array<T0> >,
-                                  negation<std::is_array<Tn> >...,
-                                  std::is_nothrow_destructible<T0>,
+  static_assert(absl::conjunction<negation<std::is_array<T0> >,
+                                  negation<std::is_array<Tn> >...>::value,
+                "Attempted to instantiate a variant containing an array type.");
+  static_assert(absl::conjunction<std::is_nothrow_destructible<T0>,
                                   std::is_nothrow_destructible<Tn>...>::value,
-                "Attempted to instantiate a variant with an unsupported type.");
+                "Attempted to instantiate a variant containing a non-nothrow "
+                "destructible type.");
 
   friend struct variant_internal::VariantCoreAccess;
 
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index b749189..21160770 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1692,7 +1692,6 @@
   kReplaceCharsetInXHR = 2230,
   kRespondToSameOriginRequestWithCrossOriginResponse = 2231,  // Obsolete.
   kLinkRelModulePreload = 2232,
-  kHTMLFrameSetElementNonNullAnonymousNamedGetter = 2235,
   kCSPWithUnsafeEval = 2236,
   kWebAssemblyInstantiation = 2237,
   kV8IndexAccessor = 2238,
@@ -1920,7 +1919,6 @@
   kShapeOutsideContentBoxDifferentFromMarginBox = 2461,
   kShapeOutsidePaddingBoxDifferentFromMarginBox = 2462,
   kCSSContainLayoutPositionedDescendants = 2463,
-  kHTMLFrameSetElementAnonymousNamedGetter = 2464,
   kCanvasConvertToBlob = 2465,
   kPolymerV1Detected = 2466,
   kPolymerV2Detected = 2467,
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.h b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
index 80a39ce..7a4f0ee 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.h
@@ -51,6 +51,7 @@
     kStreamerNotReadyOnGetSource,
     kInlineScript,
     kDidntTryToStartStreaming,
+    kErrorOccurred,
 
     // Pseudo values that should never be seen in reported metrics
     kCount,
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 35b1b1e..e5aceae3 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1705,7 +1705,6 @@
     "css/resolver/font_builder_test.cc",
     "css/resolver/font_style_resolver_test.cc",
     "css/resolver/match_result_test.cc",
-    "css/resolver/scoped_style_resolver_test.cc",
     "css/resolver/style_adjuster_test.cc",
     "css/rule_feature_set_test.cc",
     "css/rule_set_test.cc",
diff --git a/third_party/blink/renderer/core/css/ComputedStyleDiffFunctions.json5 b/third_party/blink/renderer/core/css/ComputedStyleDiffFunctions.json5
index c4866b3..4cae09bf 100644
--- a/third_party/blink/renderer/core/css/ComputedStyleDiffFunctions.json5
+++ b/third_party/blink/renderer/core/css/ComputedStyleDiffFunctions.json5
@@ -233,7 +233,6 @@
         name: "DiffNeedsPaintInvalidationSubtree",
         fields_to_diff: ["mix-blend-mode", "isolation", "Mask", "MaskBoxImage"],
     },
-
     {
         name: "DiffNeedsPaintInvalidationObject",
         fields_to_diff: ["-webkit-user-modify", "user-select", "image-rendering",
@@ -365,6 +364,10 @@
         ]
     },
     {
+        name: "UpdatePropertySpecificDifferencesMask",
+        fields_to_diff: ["Mask", "MaskBoxImage"],
+    },
+    {
         name: "UpdatePropertySpecificDifferencesNeedsRecomputeOverflow",
         predicates_to_test: [
           {
diff --git a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
index f640c14..9b9a991 100644
--- a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
+++ b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
@@ -60,8 +60,7 @@
 
   EXPECT_STREQ("rgb(0, 128, 0)",
                computed->GetPropertyValue(CSSPropertyColor).Utf8().data());
-  EXPECT_EQ(RuntimeEnabledFeatures::SlotInFlatTreeEnabled(),
-            GetDocument().NeedsLayoutTreeUpdate());
+  EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.cc b/third_party/blink/renderer/core/css/css_style_sheet.cc
index d4dbe6ad..a8c013f 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.cc
+++ b/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -92,11 +92,6 @@
 }
 
 CSSStyleSheet* CSSStyleSheet::Create(Document& document,
-                                     ExceptionState& exception_state) {
-  return CSSStyleSheet::Create(document, CSSStyleSheetInit(), exception_state);
-}
-
-CSSStyleSheet* CSSStyleSheet::Create(Document& document,
                                      const CSSStyleSheetInit& options,
                                      ExceptionState& exception_state) {
   if (!RuntimeEnabledFeatures::ConstructableStylesheetsEnabled()) {
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.h b/third_party/blink/renderer/core/css/css_style_sheet.h
index 2ee79dd..7dc0ace 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.h
+++ b/third_party/blink/renderer/core/css/css_style_sheet.h
@@ -53,7 +53,6 @@
  public:
   static const Document* SingleOwnerDocument(const CSSStyleSheet*);
 
-  static CSSStyleSheet* Create(Document&, ExceptionState&);
   static CSSStyleSheet* Create(Document&,
                                const CSSStyleSheetInit&,
                                ExceptionState&);
@@ -196,6 +195,11 @@
   FRIEND_TEST_ALL_PREFIXES(
       CSSStyleSheetTest,
       CSSStyleSheetConstructionWithNonEmptyCSSStyleSheetInit);
+  FRIEND_TEST_ALL_PREFIXES(CSSStyleSheetTest,
+                           CreateEmptyCSSStyleSheetWithEmptyCSSStyleSheetInit);
+  FRIEND_TEST_ALL_PREFIXES(
+      CSSStyleSheetTest,
+      CreateEmptyCSSStyleSheetWithNonEmptyCSSStyleSheetInit);
   FRIEND_TEST_ALL_PREFIXES(
       CSSStyleSheetTest,
       CreateCSSStyleSheetWithEmptyCSSStyleSheetInitAndText);
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.idl b/third_party/blink/renderer/core/css/css_style_sheet.idl
index b70b9fe6..1251d19 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.idl
+++ b/third_party/blink/renderer/core/css/css_style_sheet.idl
@@ -21,9 +21,6 @@
 // https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
 
 [
-    ConstructorCallWith=Document,
-    RaisesException=Constructor,
-    Constructor(optional CSSStyleSheetInit options),
     Exposed=Window
 ] interface CSSStyleSheet : StyleSheet {
     readonly attribute CSSRule? ownerRule;
diff --git a/third_party/blink/renderer/core/css/css_style_sheet_test.cc b/third_party/blink/renderer/core/css/css_style_sheet_test.cc
index d4b1bf77..234c688 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet_test.cc
+++ b/third_party/blink/renderer/core/css/css_style_sheet_test.cc
@@ -49,26 +49,12 @@
 TEST_F(CSSStyleSheetTest, ConstructorWithoutRuntimeFlagThrowsException) {
   DummyExceptionStateForTesting exception_state;
   RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(false);
-  EXPECT_EQ(CSSStyleSheet::Create(GetDocument(), exception_state), nullptr);
+  EXPECT_EQ(CSSStyleSheet::Create(GetDocument(), CSSStyleSheetInit(),
+                                  exception_state),
+            nullptr);
   ASSERT_TRUE(exception_state.HadException());
 }
 
-TEST_F(CSSStyleSheetTest, CSSStyleSheetConstructionWithEmptyCSSStyleSheetInit) {
-  DummyExceptionStateForTesting exception_state;
-  CSSStyleSheet* sheet = CSSStyleSheet::Create(GetDocument(), exception_state);
-  ASSERT_FALSE(exception_state.HadException());
-  EXPECT_TRUE(sheet->href().IsNull());
-  EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
-  EXPECT_EQ(sheet->ownerNode(), nullptr);
-  EXPECT_EQ(sheet->ownerRule(), nullptr);
-  EXPECT_EQ(sheet->media()->length(), 0U);
-  EXPECT_EQ(sheet->title(), StringImpl::empty_);
-  EXPECT_FALSE(sheet->AlternateFromConstructor());
-  EXPECT_FALSE(sheet->disabled());
-  EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
-  ASSERT_FALSE(exception_state.HadException());
-}
-
 TEST_F(CSSStyleSheetTest,
        CSSStyleSheetConstructionWithNonEmptyCSSStyleSheetInit) {
   DummyExceptionStateForTesting exception_state;
@@ -93,6 +79,48 @@
   ASSERT_FALSE(exception_state.HadException());
 }
 
+TEST_F(CSSStyleSheetTest, CreateEmptyCSSStyleSheetWithEmptyCSSStyleSheetInit) {
+  V8TestingScope scope;
+  DummyExceptionStateForTesting exception_state;
+  CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
+      scope.GetScriptState(), CSSStyleSheetInit(), exception_state);
+  ASSERT_FALSE(exception_state.HadException());
+  EXPECT_TRUE(sheet->href().IsNull());
+  EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
+  EXPECT_EQ(sheet->ownerNode(), nullptr);
+  EXPECT_EQ(sheet->ownerRule(), nullptr);
+  EXPECT_EQ(sheet->media()->length(), 0U);
+  EXPECT_EQ(sheet->title(), StringImpl::empty_);
+  EXPECT_FALSE(sheet->AlternateFromConstructor());
+  EXPECT_FALSE(sheet->disabled());
+  EXPECT_EQ(sheet->cssRules(exception_state)->length(), 0U);
+  ASSERT_FALSE(exception_state.HadException());
+}
+
+TEST_F(CSSStyleSheetTest,
+       CreateEmptyCSSStyleSheetWithNonEmptyCSSStyleSheetInit) {
+  CSSStyleSheetInit init;
+  init.setMedia(MediaListOrString::FromString("screen, print"));
+  init.setTitle("test");
+  init.setAlternate(true);
+  init.setDisabled(true);
+  V8TestingScope scope;
+  DummyExceptionStateForTesting exception_state;
+  CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
+      scope.GetScriptState(), init, exception_state);
+  ASSERT_FALSE(exception_state.HadException());
+  EXPECT_TRUE(sheet->href().IsNull());
+  EXPECT_EQ(sheet->parentStyleSheet(), nullptr);
+  EXPECT_EQ(sheet->ownerNode(), nullptr);
+  EXPECT_EQ(sheet->ownerRule(), nullptr);
+  EXPECT_EQ(sheet->media()->length(), 2U);
+  EXPECT_EQ(sheet->media()->mediaText(), init.media().GetAsString());
+  EXPECT_EQ(sheet->title(), init.title());
+  EXPECT_TRUE(sheet->AlternateFromConstructor());
+  EXPECT_TRUE(sheet->disabled());
+  ASSERT_FALSE(exception_state.HadException());
+}
+
 TEST_F(CSSStyleSheetTest,
        CreateCSSStyleSheetWithEmptyCSSStyleSheetInitAndText) {
   V8TestingScope scope;
diff --git a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc b/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
index 288b55a4..de1df7a 100644
--- a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.cc
@@ -385,28 +385,6 @@
       RuleSubSet::Create(parent_style_sheet, sheet_index, slotted_rule_set));
 }
 
-bool ScopedStyleResolver::HaveSameStyles(const ScopedStyleResolver* first,
-                                         const ScopedStyleResolver* second) {
-  // This method will return true if the two resolvers are either both empty, or
-  // if they contain the same active stylesheets by sharing the same
-  // StyleSheetContents. It is used to check if we can share ComputedStyle
-  // between two shadow hosts. This typically works when we have multiple
-  // instantiations of the same web component where the style elements are in
-  // the same order and contain the exact same source string in which case we
-  // will get a cache hit for sharing StyleSheetContents.
-
-  size_t first_count = first ? first->author_style_sheets_.size() : 0;
-  size_t second_count = second ? second->author_style_sheets_.size() : 0;
-  if (first_count != second_count)
-    return false;
-  while (first_count--) {
-    if (first->author_style_sheets_[first_count]->Contents() !=
-        second->author_style_sheets_[first_count]->Contents())
-      return false;
-  }
-  return true;
-}
-
 void ScopedStyleResolver::RuleSubSet::Trace(blink::Visitor* visitor) {
   visitor->Trace(parent_style_sheet_);
   visitor->Trace(rule_set_);
diff --git a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h b/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
index b426d49..81c2a47 100644
--- a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h
@@ -87,8 +87,6 @@
   void SetNeedsAppendAllSheets() { needs_append_all_sheets_ = true; }
   static void KeyframesRulesAdded(const TreeScope&);
   static ContainerNode& InvalidationRootForTreeScope(const TreeScope&);
-  CORE_EXPORT static bool HaveSameStyles(const ScopedStyleResolver*,
-                                         const ScopedStyleResolver*);
   void V0ShadowAddedOnV1Document();
 
   void Trace(blink::Visitor*);
diff --git a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/scoped_style_resolver_test.cc
deleted file mode 100644
index c98d5ef..0000000
--- a/third_party/blink/renderer/core/css/resolver/scoped_style_resolver_test.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/dom/shadow_root_init.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/testing/page_test_base.h"
-
-namespace blink {
-
-class ScopedStyleResolverTest : public PageTestBase {
- protected:
-  StyleEngine& GetStyleEngine() { return GetDocument().GetStyleEngine(); }
-};
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesNullNull) {
-  EXPECT_TRUE(ScopedStyleResolver::HaveSameStyles(nullptr, nullptr));
-}
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesNullEmpty) {
-  ScopedStyleResolver& resolver = GetDocument().EnsureScopedStyleResolver();
-  EXPECT_TRUE(ScopedStyleResolver::HaveSameStyles(nullptr, &resolver));
-  EXPECT_TRUE(ScopedStyleResolver::HaveSameStyles(&resolver, nullptr));
-}
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesEmptyEmpty) {
-  ScopedStyleResolver& resolver = GetDocument().EnsureScopedStyleResolver();
-  EXPECT_TRUE(ScopedStyleResolver::HaveSameStyles(&resolver, &resolver));
-}
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesNonEmpty) {
-  GetDocument().body()->SetInnerHTMLFromString(
-      "<div id=host1></div><div id=host2></div>");
-  Element* host1 = GetDocument().getElementById("host1");
-  Element* host2 = GetDocument().getElementById("host2");
-  ASSERT_TRUE(host1);
-  ASSERT_TRUE(host2);
-  ShadowRoot& root1 = host1->AttachShadowRootInternal(ShadowRootType::kOpen);
-  ShadowRoot& root2 = host2->AttachShadowRootInternal(ShadowRootType::kOpen);
-  root1.SetInnerHTMLFromString("<style>::slotted(#dummy){color:pink}</style>");
-  root2.SetInnerHTMLFromString("<style>::slotted(#dummy){color:pink}</style>");
-  GetDocument().View()->UpdateAllLifecyclePhases();
-  EXPECT_TRUE(ScopedStyleResolver::HaveSameStyles(
-      &root1.EnsureScopedStyleResolver(), &root2.EnsureScopedStyleResolver()));
-}
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesDifferentSheetCount) {
-  GetDocument().body()->SetInnerHTMLFromString(
-      "<div id=host1></div><div id=host2></div>");
-  Element* host1 = GetDocument().getElementById("host1");
-  Element* host2 = GetDocument().getElementById("host2");
-  ASSERT_TRUE(host1);
-  ASSERT_TRUE(host2);
-  ShadowRoot& root1 = host1->AttachShadowRootInternal(ShadowRootType::kOpen);
-  ShadowRoot& root2 = host2->AttachShadowRootInternal(ShadowRootType::kOpen);
-  root1.SetInnerHTMLFromString(
-      "<style>::slotted(#dummy){color:pink}</style><style>div{}</style>");
-  root2.SetInnerHTMLFromString("<style>::slotted(#dummy){color:pink}</style>");
-  GetDocument().View()->UpdateAllLifecyclePhases();
-  EXPECT_FALSE(ScopedStyleResolver::HaveSameStyles(
-      &root1.EnsureScopedStyleResolver(), &root2.EnsureScopedStyleResolver()));
-}
-
-TEST_F(ScopedStyleResolverTest, HasSameStylesCacheMiss) {
-  GetDocument().body()->SetInnerHTMLFromString(
-      "<div id=host1></div><div id=host2></div>");
-  Element* host1 = GetDocument().getElementById("host1");
-  Element* host2 = GetDocument().getElementById("host2");
-  ASSERT_TRUE(host1);
-  ASSERT_TRUE(host2);
-  ShadowRoot& root1 = host1->AttachShadowRootInternal(ShadowRootType::kOpen);
-  ShadowRoot& root2 = host2->AttachShadowRootInternal(ShadowRootType::kOpen);
-  // Style equality is detected when StyleSheetContents is shared. That is only
-  // the case when the source text is the same. The comparison will fail when
-  // adding an extra space to one of the sheets.
-  root1.SetInnerHTMLFromString("<style>::slotted(#dummy){color:pink}</style>");
-  root2.SetInnerHTMLFromString("<style>::slotted(#dummy){ color:pink}</style>");
-  GetDocument().View()->UpdateAllLifecyclePhases();
-  EXPECT_FALSE(ScopedStyleResolver::HaveSameStyles(
-      &root1.EnsureScopedStyleResolver(), &root2.EnsureScopedStyleResolver()));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index a9ff7be8..fa2f454 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2189,6 +2189,7 @@
 
   DetachPseudoElement(kPseudoIdAfter, context);
   DetachPseudoElement(kPseudoIdBackdrop, context);
+  DetachPseudoElement(kPseudoIdFirstLetter, context);
 
   if (!context.performing_reattach && IsUserActionElement()) {
     if (IsHovered())
diff --git a/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc b/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
index dbb09dae..8c310ff 100644
--- a/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
+++ b/third_party/blink/renderer/core/dom/flat_tree_traversal_test.cc
@@ -27,12 +27,9 @@
 namespace flat_tree_traversal_test {
 
 class FlatTreeTraversalTest : public PageTestBase,
-                              private ScopedSlotInFlatTreeForTest,
                               ScopedIncrementalShadowDOMForTest {
  public:
-  FlatTreeTraversalTest()
-      : ScopedSlotInFlatTreeForTest(true),
-        ScopedIncrementalShadowDOMForTest(true) {}
+  FlatTreeTraversalTest() : ScopedIncrementalShadowDOMForTest(true) {}
 
  protected:
   // Sets |mainHTML| to BODY element with |innerHTML| property and attaches
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index a9d1b695..f8d37659 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -876,10 +876,7 @@
   if (node.IsPseudoElement())
     return node.ParentOrShadowHostNode();
   if (node.IsChildOfV1ShadowHost()) {
-    HTMLSlotElement* slot = RuntimeEnabledFeatures::SlotInFlatTreeEnabled()
-                                ? node.AssignedSlot()
-                                : node.FinalDestinationSlot();
-    if (slot)
+    if (HTMLSlotElement* slot = node.AssignedSlot())
       return slot;
   }
   if (node.IsInV0ShadowTree() || node.IsChildOfV0ShadowHost()) {
@@ -1181,10 +1178,7 @@
 
 bool Node::CanParticipateInFlatTree() const {
   // TODO(hayato): Return false for pseudo elements.
-  if (RuntimeEnabledFeatures::SlotInFlatTreeEnabled()) {
     return !IsShadowRoot() && !IsActiveV0InsertionPoint(*this);
-  }
-  return !IsShadowRoot() && !IsActiveSlotOrActiveV0InsertionPoint();
 }
 
 bool Node::IsActiveSlotOrActiveV0InsertionPoint() const {
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc
index 3c4637f..1b478f2 100644
--- a/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -22,6 +22,7 @@
 #include "third_party/blink/renderer/core/editing/layout_selection.h"
 
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
@@ -293,19 +294,30 @@
   return nullptr;
 }
 
+static bool IsDisplayContentElement(const Node& node) {
+  if (!node.IsElementNode())
+    return false;
+  const ComputedStyle* const style = node.GetComputedStyle();
+  return style && style->Display() == EDisplay::kContents;
+}
+
 template <typename Visitor>
 static void VisitSelectedInclusiveDescendantsOfInternal(const Node& node,
                                                         Visitor* visitor) {
-  LayoutObject* layout_object = node.GetLayoutObject();
-  if (!layout_object)
-    return;
-  if (LayoutTextFragment* first_letter = FirstLetterPartFor(layout_object)) {
-    if (first_letter->GetSelectionState() != SelectionState::kNone)
-      visitor->Visit(first_letter);
+  // Display:content element appears in a flat tree even it doesn't have
+  // a LayoutObject but we need to visit its children.
+  if (!IsDisplayContentElement(node)) {
+    LayoutObject* layout_object = node.GetLayoutObject();
+    if (!layout_object)
+      return;
+    if (LayoutTextFragment* first_letter = FirstLetterPartFor(layout_object)) {
+      if (first_letter->GetSelectionState() != SelectionState::kNone)
+        visitor->Visit(first_letter);
+    }
+    if (layout_object->GetSelectionState() == SelectionState::kNone)
+      return;
+    visitor->Visit(layout_object);
   }
-  if (layout_object->GetSelectionState() == SelectionState::kNone)
-    return;
-  visitor->Visit(layout_object);
 
   for (Node& child : FlatTreeTraversal::ChildrenOf(node))
     VisitSelectedInclusiveDescendantsOfInternal(child, visitor);
diff --git a/third_party/blink/renderer/core/editing/layout_selection_test.cc b/third_party/blink/renderer/core/editing/layout_selection_test.cc
index f6582f5..9c8dcc3e 100644
--- a/third_party/blink/renderer/core/editing/layout_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection_test.cc
@@ -850,6 +850,35 @@
       DumpSelectionInfo());
 }
 
+// http://crbug.com/870734
+TEST_F(LayoutSelectionTest, InvalidateSlot) {
+  Selection().SetSelectionAndEndTyping(
+      SetSelectionTextToBody("^<div>"
+                             "<template data-mode=open>"
+                             "<slot></slot>"
+                             "</template>"
+                             "foo"
+                             "</div>|"));
+  UpdateAllLifecyclePhases();
+  EXPECT_EQ(
+      "BODY, Contain, NotInvalidate \n"
+      "  DIV, Contain, NotInvalidate \n"
+      "    #shadow-root \n"
+      "      SLOT, <null LayoutObject> \n"
+      "    'foo', StartAndEnd, NotInvalidate ",
+      DumpSelectionInfo());
+
+  Selection().Clear();
+  Selection().CommitAppearanceIfNeeded();
+  EXPECT_EQ(
+      "BODY, None, NotInvalidate \n"
+      "  DIV, None, NotInvalidate \n"
+      "    #shadow-root \n"
+      "      SLOT, <null LayoutObject> \n"
+      "    'foo', None, ShouldInvalidate ",
+      DumpSelectionInfo());
+}
+
 static const NGPaintFragment* FindNGPaintFragmentInternal(
     const NGPaintFragment* paint,
     const LayoutObject* layout_object) {
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index d5c2fa7..7e425b0 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -540,11 +540,6 @@
                                     "self.origin (window.origin)", kM70,
                                     "5701042356355072")};
 
-    case WebFeature::kHTMLFrameSetElementAnonymousNamedGetter:
-      return {"HTMLFrameSetElementAnonymousNamedGetter", kM70,
-              WillBeRemoved("Anonymous named getter of HTMLFrameSetElement",
-                            kM70, "5235521668251648")};
-
     case WebFeature::kMediaElementSourceOnOfflineContext:
       return {"MediaElementAudioSourceNode", kM70,
               WillBeRemoved("Creating a MediaElementAudioSourceNode on an "
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index e681cb8..69c10f7 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -848,11 +848,11 @@
   if (flags & kLayerTreeIncludesPaintInvalidations) {
     std::unique_ptr<JSONArray> object_paint_invalidations =
         view_->TrackedObjectPaintInvalidationsAsJSON();
-    if (object_paint_invalidations && object_paint_invalidations->size()) {
       if (!layers)
         layers = JSONObject::Create();
-      layers->SetArray("objectPaintInvalidations",
-                       std::move(object_paint_invalidations));
+      if (object_paint_invalidations && object_paint_invalidations->size()) {
+        layers->SetArray("objectPaintInvalidations",
+                         std::move(object_paint_invalidations));
     }
   }
 
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
index b3654203..bd294a4 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
@@ -435,9 +435,11 @@
 
 TEST_F(CustomElementRegistryTest, defineCustomElementWithStyle) {
   RuntimeEnabledFeatures::SetConstructableStylesheetsEnabled(true);
+  V8TestingScope scope;
   NonThrowableExceptionState should_not_throw;
   ElementDefinitionOptions options;
-  CSSStyleSheet* sheet = CSSStyleSheet::Create(GetDocument(), should_not_throw);
+  CSSStyleSheet* sheet = GetDocument().createEmptyCSSStyleSheet(
+      scope.GetScriptState(), CSSStyleSheetInit(), should_not_throw);
   options.setStyle(sheet);
   TestCustomElementDefinitionBuilder builder(sheet);
   CustomElementDefinition* definition_a =
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.cc b/third_party/blink/renderer/core/html/html_frame_set_element.cc
index b1a5c9e..5b97378f 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/events/mouse_event.h"
-#include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
@@ -292,23 +291,4 @@
   }
 }
 
-LocalDOMWindow* HTMLFrameSetElement::AnonymousNamedGetter(
-    const AtomicString& name) {
-  Element* frame_element = Children()->namedItem(name);
-  if (!IsHTMLFrameElement(frame_element))
-    return nullptr;
-  Document* document = ToHTMLFrameElement(frame_element)->contentDocument();
-  if (!document || !document->GetFrame())
-    return nullptr;
-
-  LocalDOMWindow* window = document->domWindow();
-  if (window) {
-    UseCounter::Count(
-        *document, WebFeature::kHTMLFrameSetElementNonNullAnonymousNamedGetter);
-  }
-  Deprecation::CountDeprecation(
-      *document, WebFeature::kHTMLFrameSetElementAnonymousNamedGetter);
-  return window;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.h b/third_party/blink/renderer/core/html/html_frame_set_element.h
index 98e44dea..b526b381 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.h
@@ -51,8 +51,6 @@
 
   bool HasNonInBodyInsertionMode() const override { return true; }
 
-  LocalDOMWindow* AnonymousNamedGetter(const AtomicString&);
-
   DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(blur);
   DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(error);
   DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(focus);
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.idl b/third_party/blink/renderer/core/html/html_frame_set_element.idl
index 372df54..c341896 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.idl
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.idl
@@ -39,7 +39,6 @@
     attribute EventHandler onscroll;
 
     // Non-standard APIs
-    [NotEnumerable] getter Window (DOMString name);
     [RuntimeEnabled=OrientationEvent] attribute EventHandler onorientationchange;
 };
 
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index ee8af18..5927c57a 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -231,7 +231,6 @@
   for (const auto& node : other.distributed_nodes_)
     distributed_indices_.Set(node.Get(), index++);
 }
-
 void HTMLSlotElement::ClearAssignedNodes() {
   DCHECK(RuntimeEnabledFeatures::IncrementalShadowDOMEnabled());
   assigned_nodes_.clear();
@@ -357,17 +356,12 @@
 // of IncementalShadowDOM.
 const HeapVector<Member<Node>>&
 HTMLSlotElement::ChildrenInFlatTreeIfAssignmentIsSupported() {
-  if (RuntimeEnabledFeatures::SlotInFlatTreeEnabled())
-    return AssignedNodes();
-  DCHECK(!NeedsDistributionRecalc());
-  return distributed_nodes_;
+  return AssignedNodes();
 }
 
 void HTMLSlotElement::DetachLayoutTree(const AttachContext& context) {
   if (SupportsAssignment()) {
-    const HeapVector<Member<Node>>& flat_tree_children =
-        RuntimeEnabledFeatures::SlotInFlatTreeEnabled() ? assigned_nodes_
-                                                        : distributed_nodes_;
+    const HeapVector<Member<Node>>& flat_tree_children = assigned_nodes_;
     for (auto& node : flat_tree_children)
       node->LazyReattachIfAttached();
   }
@@ -490,24 +484,8 @@
   HTMLElement::RemovedFrom(insertion_point);
 }
 
-void HTMLSlotElement::WillRecalcStyle(StyleRecalcChange change) {
-  if (RuntimeEnabledFeatures::SlotInFlatTreeEnabled())
-    return;
-  if (change < kIndependentInherit &&
-      GetStyleChangeType() < kSubtreeStyleChange) {
-    return;
-  }
-  for (auto& node : distributed_nodes_) {
-    node->SetNeedsStyleRecalc(
-        kLocalStyleChange,
-        StyleChangeReasonForTracing::Create(
-            StyleChangeReason::kPropagateInheritChangeToDistributedNodes));
-  }
-}
 
 void HTMLSlotElement::DidRecalcStyle(StyleRecalcChange change) {
-  if (!RuntimeEnabledFeatures::SlotInFlatTreeEnabled())
-    return;
   if (change < kIndependentInherit)
     return;
   for (auto& node : assigned_nodes_) {
diff --git a/third_party/blink/renderer/core/html/html_slot_element.h b/third_party/blink/renderer/core/html/html_slot_element.h
index e9a7f68..ffcb1a5 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.h
+++ b/third_party/blink/renderer/core/html/html_slot_element.h
@@ -136,7 +136,6 @@
 
   InsertionNotificationRequest InsertedInto(ContainerNode*) final;
   void RemovedFrom(ContainerNode*) final;
-  void WillRecalcStyle(StyleRecalcChange) final;
   void DidRecalcStyle(StyleRecalcChange) final;
 
   void EnqueueSlotChangeEvent();
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 245172b..946d717 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -287,12 +287,12 @@
           HitTestLocation adjusted_location(
               (LayoutRect(main_content_point, location.BoundingBox().Size())));
           return main_frame.GetEventHandler().HitTestResultAtLocation(
-              adjusted_location, hit_type, stop_node);
+              adjusted_location, hit_type, stop_node, no_lifecycle_update);
         } else {
           HitTestLocation adjusted_location(main_view->ConvertFromRootFrame(
               frame_view->ConvertToRootFrame(location.Point())));
           return main_frame.GetEventHandler().HitTestResultAtLocation(
-              adjusted_location, hit_type, stop_node);
+              adjusted_location, hit_type, stop_node, no_lifecycle_update);
         }
       }
     }
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index 444a6d4..e547e3f 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -384,6 +384,8 @@
       return "inline script";
     case ScriptStreamer::kDidntTryToStartStreaming:
       return "start streaming not called";
+    case ScriptStreamer::kErrorOccurred:
+      return "an error occurred";
     case ScriptStreamer::kAlreadyLoaded:
     case ScriptStreamer::kCount:
     case ScriptStreamer::kInvalid:
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
index 05f71c3..4d4bda02 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -16,6 +16,10 @@
 namespace {
 
 bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) {
+  // TODO(layout-dev): This should hit-test the intersection rect, not the
+  // target rect; it's not helpful to know that the portion of the target that
+  // is clipped is also occluded. To do that, the intersection rect must be
+  // mapped down to the local space of the target element.
   HitTestResult result(
       element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect()));
   return result.InnerNode() && result.InnerNode() != &element;
@@ -80,7 +84,8 @@
         Observer()->FirstThresholdGreaterThan(new_visible_ratio);
     if (RuntimeEnabledFeatures::IntersectionObserverV2Enabled() &&
         Observer()->trackVisibility()) {
-      is_visible = !Target()->GetLayoutObject()->HasDistortingVisualEffects() &&
+      is_visible = new_threshold_index > 0 &&
+                   !Target()->GetLayoutObject()->HasDistortingVisualEffects() &&
                    !IsOccluded(*Target(), geometry);
     }
   } else {
@@ -99,7 +104,7 @@
     IntersectionObserverEntry* new_entry = new IntersectionObserverEntry(
         timestamp, new_visible_ratio, FloatRect(geometry.TargetRect()),
         root_bounds_pointer, FloatRect(geometry.IntersectionRect()),
-        geometry.DoesIntersect(), is_visible, Target());
+        new_threshold_index > 0, is_visible, Target());
     Observer()->EnqueueIntersectionObserverEntry(*new_entry);
     SetLastThresholdIndex(new_threshold_index);
     SetWasVisible(is_visible);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 28ed3f3..313f270 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2679,7 +2679,7 @@
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
     if (const NGPaintFragment* paint_fragment = PaintFragment()) {
       NGBoxFragment box_fragment(
-          StyleRef().GetWritingMode(),
+          StyleRef().GetWritingMode(), StyleRef().Direction(),
           ToNGPhysicalBoxFragment(paint_fragment->PhysicalFragment()));
       NGLineHeightMetrics metrics =
           box_fragment.BaselineMetricsWithoutSynthesize(
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index 9e41eb9..d9de52d 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -198,8 +198,10 @@
           LayoutPoint(BorderLeft() + PaddingLeft(), BorderTop() + PaddingTop());
       HitTestLocation new_hit_test_location(
           location_in_container, -adjusted_location - content_offset);
-      HitTestRequest new_hit_test_request(result.GetHitTestRequest().GetType() |
-                                          HitTestRequest::kChildFrameHitTest);
+      HitTestRequest new_hit_test_request(
+          result.GetHitTestRequest().GetType() |
+              HitTestRequest::kChildFrameHitTest,
+          result.GetHitTestRequest().GetStopNode());
       HitTestResult child_frame_result(new_hit_test_request,
                                        new_hit_test_location);
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 0c3d6ac..76c542e 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2082,7 +2082,7 @@
   if (!IsText() && (diff.TransformChanged() || diff.OpacityChanged() ||
                     diff.ZIndexChanged() || diff.FilterChanged() ||
                     diff.BackdropFilterChanged() || diff.CssClipChanged() ||
-                    diff.BlendModeChanged())) {
+                    diff.BlendModeChanged() || diff.MaskChanged())) {
     SetNeedsPaintPropertyUpdate();
     if (HasLayer() && IsBoxModelObject()) {
       ToLayoutBoxModelObject(this)->Layer()->SetNeedsCompositingInputsUpdate();
diff --git a/third_party/blink/renderer/core/layout/layout_object_test.cc b/third_party/blink/renderer/core/layout/layout_object_test.cc
index c611605c..9f6b920 100644
--- a/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -847,4 +847,34 @@
   EXPECT_FALSE(DocumentHasTouchActionRegion(registry));
 }
 
+TEST_F(LayoutObjectSimTest, HitTestForOcclusionInIframe) {
+  SimRequest main_resource("https://example.com/test.html", "text/html");
+  SimRequest frame_resource("https://example.com/frame.html", "text/html");
+
+  LoadURL("https://example.com/test.html");
+  main_resource.Complete(R"HTML(
+    <iframe style='width:300px;height:150px;' src=frame.html></iframe>
+    <div id='occluder' style='will-change:transform;width:100px;height:100px;'>
+    </div>
+  )HTML");
+  frame_resource.Complete(R"HTML(
+    <div id='target'>target</div>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  Element* iframe_element = GetDocument().QuerySelector("iframe");
+  HTMLFrameOwnerElement* frame_owner_element =
+      ToHTMLFrameOwnerElement(iframe_element);
+  Document* iframe_doc = frame_owner_element->contentDocument();
+  Element* target = iframe_doc->getElementById("target");
+  HitTestResult result = target->GetLayoutObject()->HitTestForOcclusion();
+  EXPECT_TRUE(result.InnerNode() == target);
+
+  Element* occluder = GetDocument().getElementById("occluder");
+  occluder->SetInlineStyleProperty(CSSPropertyMarginTop, "-150px");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  result = target->GetLayoutObject()->HitTestForOcclusion();
+  EXPECT_TRUE(result.InnerNode() == occluder);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 24658d7..089fb15 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -424,7 +424,7 @@
   const NGInlineItem& item = *item_result->item;
   DCHECK(item.Style());
   NGBoxFragment fragment(
-      ConstraintSpace().GetWritingMode(),
+      ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction(),
       ToNGPhysicalBoxFragment(*item_result->layout_result->PhysicalFragment()));
   NGLineHeightMetrics metrics = fragment.BaselineMetrics(
       {NGBaselineAlgorithmType::kAtomicInline, baseline_type_},
diff --git a/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc b/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
index e41932c..92a8543b 100644
--- a/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
@@ -75,7 +75,7 @@
 
     content_metrics = line_box.Metrics();
   } else {
-    NGBoxFragment content_fragment(space.GetWritingMode(),
+    NGBoxFragment content_fragment(space.GetWritingMode(), space.Direction(),
                                    ToNGPhysicalBoxFragment(content));
     content_metrics = content_fragment.BaselineMetricsWithoutSynthesize(
         {NGBaselineAlgorithmType::kFirstLine, baseline_type});
@@ -95,7 +95,7 @@
       ToNGPhysicalBoxFragment(*marker_layout_result->PhysicalFragment());
 
   // Compute the inline offset of the marker.
-  NGBoxFragment marker_fragment(space.GetWritingMode(),
+  NGBoxFragment marker_fragment(space.GetWritingMode(), space.Direction(),
                                 marker_physical_fragment);
   NGLogicalOffset marker_offset(
       InlineOffset(marker_fragment.Size().inline_size),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 125b8f7..a4d6837f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -305,6 +305,7 @@
     DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
     NGBoxFragment fragment(
         container_writing_mode,
+        TextDirection::kLtr,  // irrelevant here
         ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
     sizes.min_size = sizes.max_size = fragment.Size().inline_size;
     return sizes;
@@ -326,6 +327,7 @@
   scoped_refptr<NGLayoutResult> layout_result = Layout(*zero_constraint_space);
   NGBoxFragment min_fragment(
       container_writing_mode,
+      TextDirection::kLtr,  // irrelevant here
       ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
   sizes.min_size = min_fragment.Size().inline_size;
 
@@ -339,6 +341,7 @@
   layout_result = Layout(*infinite_constraint_space);
   NGBoxFragment max_fragment(
       container_writing_mode,
+      TextDirection::kLtr,  // irrelevant here
       ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
   sizes.max_size = max_fragment.Size().inline_size;
   return sizes;
@@ -421,7 +424,8 @@
   const NGPhysicalBoxFragment& physical_fragment =
       ToNGPhysicalBoxFragment(*layout_result.PhysicalFragment());
 
-  NGBoxFragment fragment(constraint_space.GetWritingMode(), physical_fragment);
+  NGBoxFragment fragment(constraint_space.GetWritingMode(),
+                         constraint_space.Direction(), physical_fragment);
   NGLogicalSize fragment_logical_size = fragment.Size();
   // For each fragment we process, we'll accumulate the logical height and
   // logical intrinsic content box height. We reset it at the first fragment,
@@ -444,7 +448,7 @@
 
   NGBoxStrut borders = ComputeBorders(constraint_space, Style());
   NGBoxStrut scrollbars = GetScrollbarSizes();
-  NGBoxStrut padding = ComputePadding(constraint_space, Style());
+  NGBoxStrut padding = fragment.Padding();
   NGBoxStrut border_scrollbar_padding = borders + scrollbars + padding;
 
   if (IsLastFragment(physical_fragment))
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
index b5a5bf1..7dcf098 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
@@ -83,4 +83,10 @@
   return NGLineHeightMetrics(block_size - block_size / 2, block_size / 2);
 }
 
+NGBoxStrut NGBoxFragment::Padding() const {
+  const auto& physical_fragment = ToNGPhysicalBoxFragment(physical_fragment_);
+  return physical_fragment.Padding().ConvertToLogical(GetWritingMode(),
+                                                      direction_);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
index 93c08fc..09ebade 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
@@ -18,8 +19,9 @@
 class CORE_EXPORT NGBoxFragment final : public NGFragment {
  public:
   NGBoxFragment(WritingMode writing_mode,
+                TextDirection direction,
                 const NGPhysicalBoxFragment& physical_fragment)
-      : NGFragment(writing_mode, physical_fragment) {}
+      : NGFragment(writing_mode, physical_fragment), direction_(direction) {}
 
   // Compute baseline metrics (ascent/descent) for this box.
   //
@@ -33,6 +35,11 @@
       const NGBaselineRequest&) const;
   NGLineHeightMetrics BaselineMetrics(const NGBaselineRequest&,
                                       const NGConstraintSpace&) const;
+
+  NGBoxStrut Padding() const;
+
+ private:
+  TextDirection direction_;
 };
 
 DEFINE_TYPE_CASTS(NGBoxFragment,
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 209816b..6ae4c0f 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
@@ -131,7 +131,9 @@
         separate_leading_margins = false;
       }
 
-      LayoutUnit block_size = NGBoxFragment(writing_mode, *column).BlockSize();
+      LayoutUnit block_size =
+          NGBoxFragment(writing_mode, ConstraintSpace().Direction(), *column)
+              .BlockSize();
       intrinsic_block_size =
           std::max(intrinsic_block_size, column_block_offset + block_size);
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
index 3b6b61d..80e0055 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
@@ -308,8 +308,7 @@
   scoped_refptr<NGPhysicalBoxFragment> fragment =
       base::AdoptRef(new NGPhysicalBoxFragment(
           layout_object_, Style(), style_variant_, physical_size, children_,
-          padding_.ConvertToPhysical(GetWritingMode(), Direction())
-              .SnapToDevicePixels(),
+          padding_.ConvertToPhysical(GetWritingMode(), Direction()),
           contents_ink_overflow, baselines_, BoxType(), is_old_layout_root_,
           border_edges_.ToPhysical(GetWritingMode()), std::move(break_token)));
 
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 96198041..f6b0998 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
@@ -21,6 +21,7 @@
   if (!break_token)
     return LayoutUnit();
   NGBoxFragment logical_fragment(constraint_space.GetWritingMode(),
+                                 constraint_space.Direction(),
                                  ToNGPhysicalBoxFragment(fragment));
   return break_token->UsedBlockSize() - logical_fragment.BlockSize();
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
index bc3ab40e..9620257 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
@@ -56,7 +56,8 @@
 
     container_builder_.AddChild(result, page_offset);
 
-    NGBoxFragment logical_fragment(writing_mode, *page);
+    NGBoxFragment logical_fragment(writing_mode, ConstraintSpace().Direction(),
+                                   *page);
     intrinsic_block_size =
         std::max(intrinsic_block_size,
                  page_offset.block_offset + logical_fragment.BlockSize());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index fdb249e..aff29b78 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -22,7 +22,7 @@
     NGStyleVariant style_variant,
     NGPhysicalSize size,
     Vector<scoped_refptr<NGPhysicalFragment>>& children,
-    const NGPixelSnappedPhysicalBoxStrut& padding,
+    const NGPhysicalBoxStrut& padding,
     const NGPhysicalOffsetRect& contents_ink_overflow,
     Vector<NGBaseline>& baselines,
     NGBoxType box_type,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index a0c47ef..3e7f084 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -22,7 +22,7 @@
                         NGStyleVariant style_variant,
                         NGPhysicalSize size,
                         Vector<scoped_refptr<NGPhysicalFragment>>& children,
-                        const NGPixelSnappedPhysicalBoxStrut& padding,
+                        const NGPhysicalBoxStrut& padding,
                         const NGPhysicalOffsetRect& contents_ink_overflow,
                         Vector<NGBaseline>& baselines,
                         NGBoxType box_type,
@@ -32,7 +32,10 @@
 
   const NGBaseline* Baseline(const NGBaselineRequest&) const;
 
-  const NGPixelSnappedPhysicalBoxStrut& Padding() const { return padding_; }
+  const NGPhysicalBoxStrut& Padding() const { return padding_; }
+  NGPixelSnappedPhysicalBoxStrut PixelSnappedPadding() const {
+    return padding_.SnapToDevicePixels();
+  }
 
   bool HasSelfPaintingLayer() const;
   bool ChildrenInline() const;
@@ -69,7 +72,7 @@
 
  private:
   Vector<NGBaseline> baselines_;
-  NGPixelSnappedPhysicalBoxStrut padding_;
+  NGPhysicalBoxStrut padding_;
   NGPhysicalOffsetRect descendant_outlines_;
 };
 
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index e50a69a..ffa3a8f 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -464,16 +464,6 @@
     CompositingLayerAssigner layer_assigner(this);
     layer_assigner.Assign(update_root, layers_needing_paint_invalidation);
 
-    {
-      TRACE_EVENT0("blink",
-                   "PaintLayerCompositor::updateAfterCompositingChange");
-      if (const LocalFrameView::ScrollableAreaSet* scrollable_areas =
-              layout_view_.GetFrameView()->ScrollableAreas()) {
-        for (PaintLayerScrollableArea* scrollable_area : *scrollable_areas)
-          scrollable_area->UpdateAfterCompositingChange();
-      }
-    }
-
     if (layer_assigner.LayersChanged()) {
       update_type = std::max(update_type, kCompositingUpdateRebuildTree);
       if (ScrollingCoordinator* scrolling_coordinator =
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 5d925da..bdaa022 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -796,7 +796,8 @@
 
 LayoutRectOutsets NGBoxFragmentPainter::ComputePadding() const {
   return BoxStrutToLayoutRectOutsets(
-      ToNGPhysicalBoxFragment(box_fragment_.PhysicalFragment()).Padding());
+      ToNGPhysicalBoxFragment(box_fragment_.PhysicalFragment())
+          .PixelSnappedPadding());
 }
 
 BoxPainterBase::FillLayerInfo NGBoxFragmentPainter::GetFillLayerInfo(
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 687d40b..13e0c5d5 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -151,7 +151,6 @@
       needs_ancestor_dependent_compositing_inputs_update_(true),
       child_needs_compositing_inputs_update_(true),
       has_compositing_descendant_(false),
-      is_all_scrolling_content_composited_(false),
       should_isolate_composited_descendants_(false),
       lost_grouped_mapping_(false),
       needs_repaint_(false),
@@ -704,34 +703,6 @@
   }
 }
 
-// FIXME: this is quite brute-force. We could be more efficient if we were to
-// track state and update it as appropriate as changes are made in the layout
-// tree.
-void PaintLayer::UpdateScrollingStateAfterCompositingChange() {
-  TRACE_EVENT0("blink",
-               "PaintLayer::updateScrollingStateAfterCompositingChange");
-  is_all_scrolling_content_composited_ = true;
-  for (LayoutObject* r = GetLayoutObject().SlowFirstChild(); r;
-       r = r->NextSibling()) {
-    if (!r->HasLayer()) {
-      is_all_scrolling_content_composited_ = false;
-      return;
-    }
-  }
-
-  for (PaintLayer* child = FirstChild(); child; child = child->NextSibling()) {
-    if (child->GetCompositingState() == kNotComposited) {
-      is_all_scrolling_content_composited_ = false;
-      return;
-    } else if (!child->GetLayoutObject().StyleRef().IsStackingContext()) {
-      // If the child is composited, but not a stacking context, it may paint
-      // negative z-index descendants into an ancestor's GraphicsLayer.
-      is_all_scrolling_content_composited_ = false;
-      return;
-    }
-  }
-}
-
 void PaintLayer::UpdateDescendantDependentFlags() {
   if (needs_descendant_dependent_flags_update_) {
     bool old_has_non_isolated_descendant_with_blend_mode =
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 2b67369..b3c274b1 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -353,12 +353,6 @@
   // True if this layer container layoutObjects that paint.
   bool HasNonEmptyChildLayoutObjects() const;
 
-  // Will ensure that isAllScrollingContentComposited() is up to date.
-  void UpdateScrollingStateAfterCompositingChange();
-  bool IsAllScrollingContentComposited() const {
-    return is_all_scrolling_content_composited_;
-  }
-
   // Gets the ancestor layer that serves as the containing block (in the sense
   // of LayoutObject::container() instead of LayoutObject::containingBlock())
   // of this layer. Normally the parent layer is the containing layer, except
@@ -1275,11 +1269,6 @@
   // the tree of z-order lists.
   unsigned has_compositing_descendant_ : 1;
 
-  // True iff we have scrollable overflow and all children of layout_object_ are
-  // known to paint exclusively into their own composited layers.  Set by
-  // updateScrollingStateAfterCompositingChange().
-  unsigned is_all_scrolling_content_composited_ : 1;
-
   // Should be for stacking contexts having unisolated blending descendants.
   unsigned should_isolate_composited_descendants_ : 1;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 2c9bbb7f..766fd23 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -509,18 +509,25 @@
 
 void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange(
     bool offset_was_zero) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
-    // "background-attachment: local" causes the background of this element to
-    // change position due to scroll so a paint invalidation is needed.
-    // TODO(pdr): This invalidation can be removed if the local background
-    // attachment is painted into the scrolling contents.
-    if (ScrollsOverflow() &&
-        GetLayoutBox()->Style()->BackgroundLayers().Attachment() ==
-            EFillAttachment::kLocal) {
+  bool requires_paint_invalidation = false;
+
+  // "background-attachment: local" causes the background of this element to
+  // change position due to scroll so a paint invalidation is needed.
+  // TODO(pdr): This invalidation can be removed if the local background
+  // attachment is painted into the scrolling contents.
+  if (ScrollsOverflow() &&
+      GetLayoutBox()->Style()->BackgroundLayers().Attachment() ==
+          EFillAttachment::kLocal) {
+    if (!UsesCompositedScrolling())
+      requires_paint_invalidation = true;
+
+    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
       GetLayoutBox()->SetShouldDoFullPaintInvalidation();
       return;
     }
+  }
 
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
     // TODO(pdr): If this is the root frame, descendants with fixed background
     // attachments need to be invalidated.
 
@@ -537,32 +544,17 @@
     // PaintLayer to just check for interest rect changes instead of doing a
     // full repaint.
     bool needs_repaint_for_interest_rect = true;
-    if (needs_repaint_for_overflow_hidden || needs_repaint_for_interest_rect) {
+    if (needs_repaint_for_overflow_hidden || needs_repaint_for_interest_rect)
       Layer()->SetNeedsRepaint();
-      return;
-    }
 
     return;
   }
 
-  bool requires_paint_invalidation = true;
-
   LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
   bool is_root_layer = Layer()->IsRootLayer();
-  if (GetLayoutBox()->View()->Compositor()->InCompositingMode()) {
-    bool only_scrolled_composited_layers =
-        ScrollsOverflow() && Layer()->IsAllScrollingContentComposited() &&
-        GetLayoutBox()->Style()->BackgroundLayers().Attachment() !=
-            EFillAttachment::kLocal;
+  frame_view->InvalidateBackgroundAttachmentFixedDescendants(*GetLayoutBox());
 
-    if (UsesCompositedScrolling() || only_scrolled_composited_layers)
-      requires_paint_invalidation = false;
-  }
-
-  if (requires_paint_invalidation || is_root_layer)
-    frame_view->InvalidateBackgroundAttachmentFixedDescendants(*GetLayoutBox());
-
-  if (!requires_paint_invalidation && is_root_layer) {
+  if (is_root_layer) {
     // Some special invalidations for the root layer.
     if (frame_view->HasViewportConstrainedObjects()) {
       if (!frame_view->InvalidateViewportConstrainedObjects())
@@ -574,6 +566,13 @@
   if (requires_paint_invalidation) {
     GetLayoutBox()->SetShouldDoFullPaintInvalidation();
     GetLayoutBox()->SetMayNeedPaintInvalidationSubtree();
+  } else if (!UsesCompositedScrolling()) {
+    // If any scrolling content might have ben clipped by a cull rect, then
+    // that cull rect could be affected by scroll offset. For composited
+    // scrollers, this will be taken care of by the interest rect computation
+    // in CompositedLayerMapping.
+    // TODO(chrishtr): replace this shortcut with interest rects.
+    Layer()->SetNeedsRepaint();
   }
 }
 
@@ -1222,10 +1221,6 @@
   UpdateResizerStyle(old_style);
 }
 
-void PaintLayerScrollableArea::UpdateAfterCompositingChange() {
-  Layer()->UpdateScrollingStateAfterCompositingChange();
-}
-
 void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
   UpdateScrollDimensions();
   UpdateScrollbarProportions();
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 11fbcd3..b11c19df 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -378,8 +378,6 @@
   void UpdateAfterStyleChange(const ComputedStyle*);
   void UpdateAfterOverflowRecalc();
 
-  void UpdateAfterCompositingChange();
-
   bool HasScrollbar() const {
     return HasHorizontalScrollbar() || HasVerticalScrollbar();
   }
diff --git a/third_party/blink/renderer/core/script/classic_pending_script.cc b/third_party/blink/renderer/core/script/classic_pending_script.cc
index a08c15b..b34d5f65 100644
--- a/third_party/blink/renderer/core/script/classic_pending_script.cc
+++ b/third_party/blink/renderer/core/script/classic_pending_script.cc
@@ -380,11 +380,13 @@
     DCHECK_EQ(not_streamed_reason, ScriptStreamer::kInvalid);
     if (streamer_->StreamingSuppressed()) {
       not_streamed_reason = streamer_->StreamingSuppressedReason();
-    } else if (ready_state_ != kReady) {
-      DCHECK_EQ(ready_state_, kReadyStreaming);
+    } else if (ready_state_ == kErrorOccurred) {
+      not_streamed_reason = ScriptStreamer::kErrorOccurred;
+    } else if (ready_state_ == kReadyStreaming) {
       not_streamed_reason = ScriptStreamer::kStreamerNotReadyOnGetSource;
     } else {
       // Streamer can be used to compile script.
+      DCHECK_EQ(ready_state_, kReady);
       streamer_ready = true;
     }
   }
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index c6aa9af24..c20bd46 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -814,6 +814,9 @@
     diff.SetTextDecorationOrColorChanged();
   }
 
+  if (ComputedStyleBase::UpdatePropertySpecificDifferencesMask(*this, other))
+    diff.SetMaskChanged();
+
   bool has_clip = HasOutOfFlowPosition() && !HasAutoClip();
   bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip();
   if (has_clip != other_has_clip ||
diff --git a/third_party/blink/renderer/core/style/style_difference.h b/third_party/blink/renderer/core/style/style_difference.h
index 356d6810..2d9e013 100644
--- a/third_party/blink/renderer/core/style/style_difference.h
+++ b/third_party/blink/renderer/core/style/style_difference.h
@@ -27,6 +27,7 @@
     // decorations or properties dependent on color (e.g., border or outline).
     kTextDecorationOrColorChanged = 1 << 6,
     kBlendModeChanged = 1 << 7,
+    kMaskChanged = 1 << 8,
     // If you add a value here, be sure to update kPropertyDifferenceCount.
   };
 
@@ -146,6 +147,11 @@
     property_specific_differences_ |= kTextDecorationOrColorChanged;
   }
 
+  bool MaskChanged() const {
+    return property_specific_differences_ & kMaskChanged;
+  }
+  void SetMaskChanged() { property_specific_differences_ |= kMaskChanged; }
+
   bool ScrollAnchorDisablingPropertyChanged() const {
     return scroll_anchor_disabling_property_changed_;
   }
@@ -156,7 +162,7 @@
   void SetCompositingReasonsChanged() { composited_reasons_changed_ = true; }
 
  private:
-  static constexpr int kPropertyDifferenceCount = 8;
+  static constexpr int kPropertyDifferenceCount = 9;
 
   friend CORE_EXPORT std::ostream& operator<<(std::ostream&,
                                               const StyleDifference&);
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPopoverHelper.js b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPopoverHelper.js
index 5fe611e..44b1ee9 100644
--- a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPopoverHelper.js
+++ b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPopoverHelper.js
@@ -71,7 +71,8 @@
         const titleElement = popoverContentElement.createChild('div', 'monospace object-popover-title');
         titleElement.createChild('span').textContent = description;
         linkifier = new Components.Linkifier();
-        const section = new ObjectUI.ObjectPropertiesSection(result, '', linkifier);
+        const section = new ObjectUI.ObjectPropertiesSection(
+            result, '', linkifier, undefined, undefined, undefined, true /* showOverflow */);
         section.element.classList.add('object-popover-tree');
         section.titleLessMode();
         popoverContentElement.appendChild(section.element);
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css b/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
index fe10ae09..2ce0756a 100644
--- a/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
+++ b/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
@@ -54,6 +54,7 @@
 .name-and-value {
     overflow-x: hidden;
     text-overflow: ellipsis;
+    line-height: normal;
 }
 
 .editing-sub-part .name-and-value {
diff --git a/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js b/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
index 7cf6d2f..376b50d 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/ARIAUtils.js
@@ -56,6 +56,20 @@
 /**
  * @param {!Element} element
  */
+UI.ARIAUtils.markAsMenu = function(element) {
+  element.setAttribute('role', 'menu');
+};
+
+/**
+ * @param {!Element} element
+ */
+UI.ARIAUtils.markAsMenuItem = function(element) {
+  element.setAttribute('role', 'menuitem');
+};
+
+/**
+ * @param {!Element} element
+ */
 UI.ARIAUtils.markAsHidden = function(element) {
   element.setAttribute('aria-hidden', 'true');
 };
diff --git a/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js b/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
index 65da0ee..759b485 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/ContextMenu.js
@@ -434,8 +434,7 @@
 
   _innerShow() {
     const menuObject = this._buildMenuDescriptors();
-    if (this._useSoftMenu || UI.ContextMenu._useSoftMenu || InspectorFrontendHost.isHostedMode() ||
-        (UI.themeSupport.hasTheme() && menuObject.length)) {
+    if (this._useSoftMenu || UI.ContextMenu._useSoftMenu || InspectorFrontendHost.isHostedMode()) {
       this._softMenu = new UI.SoftContextMenu(menuObject, this._itemSelected.bind(this));
       this._softMenu.show(this._event.target.ownerDocument, new AnchorBox(this._x, this._y, 0, 0));
     } else {
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SoftContextMenu.js b/third_party/blink/renderer/devtools/front_end/ui/SoftContextMenu.js
index 1f2a605..aff0106c 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/SoftContextMenu.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/SoftContextMenu.js
@@ -36,6 +36,8 @@
     this._items = items;
     this._itemSelectedCallback = itemSelectedCallback;
     this._parentMenu = parentMenu;
+    /** @type {?Element} */
+    this._highlightedMenuItemElement = null;
   }
 
   /**
@@ -60,7 +62,8 @@
         this._parentMenu ? UI.GlassPane.AnchorBehavior.PreferRight : UI.GlassPane.AnchorBehavior.PreferBottom);
 
     this._contextMenuElement = this._glassPane.contentElement.createChild('div', 'soft-context-menu');
-    this._contextMenuElement.tabIndex = 0;
+    this._contextMenuElement.tabIndex = -1;
+    UI.ARIAUtils.markAsMenu(this._contextMenuElement);
     this._contextMenuElement.addEventListener('mouseup', e => e.consume(), false);
     this._contextMenuElement.addEventListener('keydown', this._menuKeyDown.bind(this), false);
 
@@ -106,6 +109,8 @@
       return this._createSubMenu(item);
 
     const menuItemElement = createElementWithClass('div', 'soft-context-menu-item');
+    menuItemElement.tabIndex = -1;
+    UI.ARIAUtils.markAsMenuItem(menuItemElement);
     const checkMarkElement = UI.Icon.create('smallicon-checkmark', 'checkmark');
     menuItemElement.appendChild(checkMarkElement);
     if (!item.checked)
@@ -131,12 +136,22 @@
     menuItemElement.addEventListener('mouseleave', this._menuItemMouseLeave.bind(this), false);
 
     menuItemElement._actionId = item.id;
+
+    let accessibleName = item.label;
+    if (item.checked)
+      accessibleName += ', checked';
+    if (item.shortcut)
+      accessibleName += ', ' + item.shortcut;
+    UI.ARIAUtils.setAccessibleName(menuItemElement, accessibleName);
+
     return menuItemElement;
   }
 
   _createSubMenu(item) {
     const menuItemElement = createElementWithClass('div', 'soft-context-menu-item');
     menuItemElement._subItems = item.subItems;
+    menuItemElement.tabIndex = -1;
+    UI.ARIAUtils.markAsMenuItem(menuItemElement);
 
     // Occupy the same space on the left in all items.
     const checkMarkElement = UI.Icon.create('smallicon-checkmark', 'soft-context-menu-item-checkmark');
@@ -262,7 +277,7 @@
       if (UI.themeSupport.hasTheme() || Host.isMac())
         this._highlightedMenuItemElement.classList.add('force-white-icons');
       this._highlightedMenuItemElement.classList.add('soft-context-menu-item-mouse-over');
-      this._contextMenuElement.focus();
+      this._highlightedMenuItemElement.focus();
       if (scheduleSubMenu && this._highlightedMenuItemElement._subItems &&
           !this._highlightedMenuItemElement._subMenuTimer) {
         this._highlightedMenuItemElement._subMenuTimer =
@@ -274,7 +289,9 @@
   _highlightPrevious() {
     let menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.previousSibling :
                                                              this._contextMenuElement.lastChild;
-    while (menuItemElement && (menuItemElement._isSeparator || menuItemElement._isCustom))
+    while (menuItemElement &&
+           (menuItemElement._isSeparator || menuItemElement._isCustom ||
+            menuItemElement.classList.contains('soft-context-menu-disabled')))
       menuItemElement = menuItemElement.previousSibling;
     if (menuItemElement)
       this._highlightMenuItem(menuItemElement, false);
@@ -283,7 +300,9 @@
   _highlightNext() {
     let menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.nextSibling :
                                                              this._contextMenuElement.firstChild;
-    while (menuItemElement && (menuItemElement._isSeparator || menuItemElement._isCustom))
+    while (menuItemElement &&
+           (menuItemElement._isSeparator || menuItemElement._isCustom ||
+            menuItemElement.classList.contains('soft-context-menu-disabled')))
       menuItemElement = menuItemElement.nextSibling;
     if (menuItemElement)
       this._highlightMenuItem(menuItemElement, false);
diff --git a/third_party/blink/renderer/modules/budget/budget_service.idl b/third_party/blink/renderer/modules/budget/budget_service.idl
index 9f3e6c76..22cdb21 100644
--- a/third_party/blink/renderer/modules/budget/budget_service.idl
+++ b/third_party/blink/renderer/modules/budget/budget_service.idl
@@ -9,7 +9,6 @@
 };
 
 [
-    RuntimeEnabled=Budget,
     SecureContext,
     Exposed=(Window,Worker)
 ] interface BudgetService {
diff --git a/third_party/blink/renderer/modules/budget/navigator_budget.idl b/third_party/blink/renderer/modules/budget/navigator_budget.idl
index 525dc1de..b94d0d96 100644
--- a/third_party/blink/renderer/modules/budget/navigator_budget.idl
+++ b/third_party/blink/renderer/modules/budget/navigator_budget.idl
@@ -5,8 +5,7 @@
 // https://wicg.github.io/budget-api/#navigator-workernavigator-extensions
 
 [
-    ImplementedAs=NavigatorBudget,
-    RuntimeEnabled=Budget
+    ImplementedAs=NavigatorBudget
 ] partial interface Navigator {
     [SameObject, CallWith=ExecutionContext] readonly attribute BudgetService budget;
 };
diff --git a/third_party/blink/renderer/modules/budget/worker_navigator_budget.idl b/third_party/blink/renderer/modules/budget/worker_navigator_budget.idl
index 8f4f2b51..86677a2 100644
--- a/third_party/blink/renderer/modules/budget/worker_navigator_budget.idl
+++ b/third_party/blink/renderer/modules/budget/worker_navigator_budget.idl
@@ -5,8 +5,7 @@
 // https://wicg.github.io/budget-api/#navigator-workernavigator-extensions
 
 [
-    ImplementedAs=WorkerNavigatorBudget,
-    RuntimeEnabled=Budget
+    ImplementedAs=WorkerNavigatorBudget
 ] partial interface WorkerNavigator {
     [SameObject, CallWith=ExecutionContext] readonly attribute BudgetService budget;
 };
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index 0d07598..247682f6 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -383,6 +383,15 @@
   transition: opacity 0.25s cubic-bezier(0.25, 0.1, 0.25, 1);
 }
 
+/**
+ * The overlay-play-button is disabled if the video element is loaded via
+ * MHTML, and a ruleset for input[type=button]:disabled in themeWin.css has
+ * higher priority than the above ruleset.
+ */
+video::-webkit-media-controls-overlay-play-button:disabled {
+  background: transparent;
+}
+
 video::-webkit-media-controls-overlay-play-button.hidden {
   opacity: 0;
   transition: opacity 0.75s cubic-bezier(0.25, 0.1, 0.25, 1);
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 0eae7b43..46150507 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -219,6 +219,7 @@
           "peerconnection/rtc_data_channel.idl",
           "peerconnection/rtc_data_channel_event.idl",
           "peerconnection/rtc_ice_candidate.idl",
+          "peerconnection/rtc_ice_transport.idl",
           "peerconnection/rtc_legacy_stats_report.idl",
           "peerconnection/rtc_peer_connection.idl",
           "peerconnection/rtc_peer_connection_ice_event.idl",
@@ -591,6 +592,8 @@
           "peerconnection/rtc_dtmf_tone_change_event_init.idl",
           "peerconnection/rtc_data_channel_init.idl",
           "peerconnection/rtc_ice_candidate_init.idl",
+          "peerconnection/rtc_ice_candidate_pair.idl",
+          "peerconnection/rtc_ice_parameters.idl",
           "peerconnection/rtc_ice_server.idl",
           "peerconnection/rtc_offer_answer_options.idl",
           "peerconnection/rtc_offer_options.idl",
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 487384a..d057a3a5 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -52,7 +52,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/feature_policy/feature_policy.h"
 #include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
@@ -518,8 +517,7 @@
     if (exception_state.HadException())
       exception_state.ClearException();
   }
-  if (RuntimeEnabledFeatures::PaymentRequestBasicCardEnabled() &&
-      supported_method == "basic-card") {
+  if (supported_method == "basic-card") {
     SetBasicCardMethodData(input, output, exception_state);
     if (exception_state.HadException())
       exception_state.ClearException();
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index 924ebf1e..5413f86 100644
--- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -20,6 +20,8 @@
     "rtc_error_util.h",
     "rtc_ice_candidate.cc",
     "rtc_ice_candidate.h",
+    "rtc_ice_transport.cc",
+    "rtc_ice_transport.h",
     "rtc_legacy_stats_report.cc",
     "rtc_legacy_stats_report.h",
     "rtc_peer_connection.cc",
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_pair.idl b/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_pair.idl
new file mode 100644
index 0000000..56681878
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_pair.idl
@@ -0,0 +1,9 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcicecandidatepair
+dictionary RTCIceCandidatePair {
+    RTCIceCandidate local;
+    RTCIceCandidate remote;
+};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.idl b/third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.idl
new file mode 100644
index 0000000..4598ce85
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.idl
@@ -0,0 +1,9 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtciceparameters
+dictionary RTCIceParameters {
+    DOMString usernameFragment;
+    DOMString password;
+};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
new file mode 100644
index 0000000..aef2f13
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.h"
+
+namespace blink {
+
+RTCIceTransport* RTCIceTransport::Create() {
+  return new RTCIceTransport();
+}
+
+RTCIceTransport::RTCIceTransport() = default;
+
+String RTCIceTransport::role() const {
+  return String();
+}
+
+String RTCIceTransport::state() const {
+  return "new";
+}
+
+String RTCIceTransport::gatheringState() const {
+  return "new";
+}
+
+const HeapVector<Member<RTCIceCandidate>>& RTCIceTransport::getLocalCandidates()
+    const {
+  return local_candidates_;
+}
+
+const HeapVector<Member<RTCIceCandidate>>&
+RTCIceTransport::getRemoteCandidates() const {
+  return remote_candidates_;
+}
+
+void RTCIceTransport::getSelectedCandidatePair(
+    base::Optional<RTCIceCandidatePair>& result) const {
+  result = selected_candidate_pair_;
+}
+
+void RTCIceTransport::getLocalParameters(
+    base::Optional<RTCIceParameters>& result) const {
+  result = base::nullopt;
+}
+
+void RTCIceTransport::getRemoteParameters(
+    base::Optional<RTCIceParameters>& result) const {
+  result = base::nullopt;
+}
+
+void RTCIceTransport::Trace(blink::Visitor* visitor) {
+  visitor->Trace(local_candidates_);
+  visitor->Trace(remote_candidates_);
+  visitor->Trace(selected_candidate_pair_);
+  ScriptWrappable::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
new file mode 100644
index 0000000..d6a3983
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_H_
+
+#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_candidate_pair.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_pair.h"
+#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.h"
+
+namespace blink {
+
+class RTCIceCandidate;
+
+// Blink bindings for the RTCIceTransport JavaScript object.
+class MODULES_EXPORT RTCIceTransport final : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static RTCIceTransport* Create();
+
+  // rtc_ice_transport.idl
+  String role() const;
+  String state() const;
+  String gatheringState() const;
+  const HeapVector<Member<RTCIceCandidate>>& getLocalCandidates() const;
+  const HeapVector<Member<RTCIceCandidate>>& getRemoteCandidates() const;
+  void getSelectedCandidatePair(
+      base::Optional<RTCIceCandidatePair>& result) const;
+  void getLocalParameters(base::Optional<RTCIceParameters>& result) const;
+  void getRemoteParameters(base::Optional<RTCIceParameters>& result) const;
+
+  // For garbage collection.
+  void Trace(blink::Visitor* visitor) override;
+
+ private:
+  RTCIceTransport();
+
+  HeapVector<Member<RTCIceCandidate>> local_candidates_;
+  HeapVector<Member<RTCIceCandidate>> remote_candidates_;
+  base::Optional<RTCIceCandidatePair> selected_candidate_pair_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
new file mode 100644
index 0000000..e87051e
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcicerole
+enum RTCIceRole {
+    "controlling",
+    "controlled",
+};
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcicetransportstate
+enum RTCIceTransportState {
+    "new",
+    "checking",
+    "connected",
+    "completed",
+    "disconnected",
+    "failed",
+    "closed",
+};
+
+// https://w3c.github.io/webrtc-pc/#dom-rtcicegatheringstate
+enum RTCIceGatheringState {
+    "new",
+    "gathering",
+    "complete"
+};
+
+// https://w3c.github.io/webrtc-pc/#rtcicetransport
+[
+   // Constructor from https://w3c.github.io/webrtc-ice/#rtcicetransport*
+   Constructor(),
+   Exposed=Window,
+   RuntimeEnabled=RTCIceTransportExtension
+] interface RTCIceTransport {
+    // TODO(github.com/w3c/webrtc-ice/issues/4): role is non-null in the
+    // WebRTC-PC specification.
+    readonly attribute RTCIceRole? role;
+    readonly attribute RTCIceTransportState state;
+    readonly attribute RTCIceGatheringState gatheringState;
+    sequence<RTCIceCandidate> getLocalCandidates();
+    sequence<RTCIceCandidate> getRemoteCandidates();
+    RTCIceCandidatePair? getSelectedCandidatePair();
+    RTCIceParameters? getLocalParameters();
+    RTCIceParameters? getRemoteParameters();
+
+    // TODO(crbug.com/864871): Add events and extension methods.
+};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
index 35913ca..dc3060f 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
@@ -39,12 +39,6 @@
     "closed"
 };
 
-enum RTCIceGatheringState {
-    "new",
-    "gathering",
-    "complete"
-};
-
 enum RTCIceConnectionState {
     "new",
     "checking",
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc
index d6513fa..771340b 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.cc
+++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -129,7 +129,6 @@
 }
 
 void VRDisplay::Update(const device::mojom::blink::VRDisplayInfoPtr& display) {
-  display_id_ = display->index;
   display_name_ = display->displayName;
   is_connected_ = true;
 
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h
index 462d066..5cd4aee 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.h
+++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -163,7 +163,6 @@
       std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
 
   Member<NavigatorVR> navigator_vr_;
-  unsigned display_id_ = 0;
   String display_name_;
   bool is_connected_ = false;
   bool is_presenting_ = false;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 4bddb688..b470acd 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -4216,7 +4216,7 @@
 }
 
 GLboolean WebGL2RenderingContextBase::isSync(WebGLSync* sync) {
-  if (isContextLost() || !sync)
+  if (isContextLost() || !sync || !sync->Validate(ContextGroup(), this))
     return 0;
 
   return sync->Object() != 0;
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.cc b/third_party/blink/renderer/platform/heap/heap_allocator.cc
index 7791505..411f19a 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.cc
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.cc
@@ -40,8 +40,10 @@
   BackingFree(address);
 }
 
-void HeapAllocator::FreeHashTableBacking(void* address, bool is_weak_table) {
-  if (!ThreadState::Current()->IsMarkingInProgress() || !is_weak_table)
+void HeapAllocator::FreeHashTableBacking(void* address) {
+  // When incremental marking is enabled weak callbacks may have been
+  // registered.
+  if (!ThreadState::Current()->IsMarkingInProgress())
     BackingFree(address);
 }
 
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index 8e72066..116a9e0 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -125,7 +125,7 @@
   static T* AllocateZeroedHashTableBacking(size_t size) {
     return AllocateHashTableBacking<T, HashTable>(size);
   }
-  static void FreeHashTableBacking(void* address, bool is_weak_table);
+  static void FreeHashTableBacking(void* address);
   static bool ExpandHashTableBacking(void*, size_t);
 
   static void TraceMarkedBackingStore(void* address) {
diff --git a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
index 3b0f678..4bc04a8 100644
--- a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -1695,6 +1695,28 @@
   CHECK_EQ(1u, count);
 }
 
+TEST(IncrementalMarkingTest, NoBackingFreeDuringIncrementalMarking) {
+  // Regression test: https://crbug.com/870306
+  // Only reproduces in ASAN configurations.
+  using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>;
+
+  Persistent<WeakStore> persistent(new WeakStore);
+  // Prefill the collection to grow backing store. A new backing store allocaton
+  // would trigger the write barrier, mitigating the bug where a backing store
+  // is promptly freed.
+  for (size_t i = 0; i < 8; i++) {
+    persistent->insert({Object::Create(), i});
+  }
+  IncrementalMarkingTestDriver driver(ThreadState::Current());
+  driver.Start();
+  persistent->insert({Object::Create(), 8});
+  // Is not allowed to free the backing store as the previous insert may have
+  // registered a slot.
+  persistent->clear();
+  driver.FinishSteps();
+  driver.FinishGC();
+}
+
 }  // namespace incremental_marking_test
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 551c0a7..bd30c224 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -823,6 +823,7 @@
 
 void ResourceLoader::Dispose() {
   loader_ = nullptr;
+  progress_binding_.Close();
 
   // Release() should be called to release |scheduler_client_id_| beforehand in
   // DidFinishLoading() or DidFail(), but when a timer to call Cancel() is
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index e25326b..fcddb4c3 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -147,10 +147,6 @@
       status: "stable"
     },
     {
-      name: "Budget",
-      status: "stable",
-    },
-    {
       name: "BudgetQuery",
       origin_trial_feature_name: "BudgetQuery",
       status: "experimental",
@@ -935,10 +931,6 @@
       status: "experimental",
     },
     {
-      name: "PaymentRequestBasicCard",
-      status: "stable",
-    },
-    {
       name: "PaymentRetry",
       status: "experimental",
     },
@@ -1061,6 +1053,11 @@
       name: "RestrictCanRequestURLCharacterSet",
       status: "stable",
     },
+    // Enables the use of the RTCIceTransport with extensions.
+    {
+      name: "RTCIceTransportExtension",
+      status: "test",
+    },
     {
       name: "RtcPeerConnectionId",
       origin_trial_feature_name: "RtcPeerConnectionId",
@@ -1165,10 +1162,6 @@
       name: "SlimmingPaintV2",
     },
     {
-      name: "SlotInFlatTree",
-      status: "stable",
-    },
-    {
       name: "SMIL",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
index 8d56b92..ae458f1 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -147,6 +147,10 @@
   return base::TimeTicks::Now();
 }
 
+void SchedulerHelper::SetTimerSlack(base::TimerSlack timer_slack) {
+  sequence_manager_->SetTimerSlack(timer_slack);
+}
+
 double SchedulerHelper::GetSamplingRateForRecordingCPUTime() const {
   if (sequence_manager_) {
     return sequence_manager_->GetMetricRecordingSettings()
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
index 2cb6a3e..577f1ed 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
@@ -33,6 +33,7 @@
 
   const base::TickClock* GetClock() const;
   base::TimeTicks NowTicks() const;
+  void SetTimerSlack(base::TimerSlack timer_slack);
 
   // Returns the default task queue.
   virtual scoped_refptr<base::sequence_manager::TaskQueue>
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index eb714f7..bc28d0a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -958,6 +958,13 @@
 
 void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) {
   helper_.CheckOnValidThread();
+
+  // Increasing timer slack helps the OS to coalesce timers efficiently.
+  base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
+  if (backgrounded)
+    timer_slack = base::TIMER_SLACK_MAXIMUM;
+  helper_.SetTimerSlack(timer_slack);
+
   if (helper_.IsShutdown() ||
       main_thread_only().renderer_backgrounded == backgrounded)
     return;
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.cc b/third_party/blink/renderer/platform/text/text_break_iterator.cc
index 28fb948..c9920471 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -59,8 +59,7 @@
   if (!length)
     return;
 
-  String string = text.ToString();
-  NonSharedCharacterBreakIterator it(string);
+  NonSharedCharacterBreakIterator it(text);
   int cursor_pos = it.Next();
   unsigned count = 0;
   unsigned pos = 0;
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.h b/third_party/blink/renderer/platform/text/text_break_iterator.h
index 3fa2f390..dee25350 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator.h
+++ b/third_party/blink/renderer/platform/text/text_break_iterator.h
@@ -315,7 +315,7 @@
   STACK_ALLOCATED();
 
  public:
-  explicit NonSharedCharacterBreakIterator(const String&);
+  explicit NonSharedCharacterBreakIterator(const StringView&);
   NonSharedCharacterBreakIterator(const UChar*, unsigned length);
   ~NonSharedCharacterBreakIterator();
 
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
index 327c6f9..1a5c8e0b 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
@@ -751,7 +751,7 @@
 }
 
 NonSharedCharacterBreakIterator::NonSharedCharacterBreakIterator(
-    const String& string)
+    const StringView& string)
     : is8_bit_(true),
       charaters8_(nullptr),
       offset_(0),
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.cc b/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.cc
index bb4fd19f..30686ea6 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.cc
@@ -17,8 +17,7 @@
   Partitions::BufferFree(address);
 }
 
-void PartitionAllocator::FreeHashTableBacking(void* address,
-                                              bool is_weak_table) {
+void PartitionAllocator::FreeHashTableBacking(void* address) {
   Partitions::BufferFree(address);
 }
 
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h b/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
index cbd0f90..bcfff867 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h
@@ -82,7 +82,7 @@
     memset(result, 0, size);
     return reinterpret_cast<T*>(result);
   }
-  static void FreeHashTableBacking(void* address, bool is_weak_table);
+  static void FreeHashTableBacking(void* address);
 
   template <typename Return, typename Metadata>
   static Return Malloc(size_t size, const char* type_name) {
diff --git a/third_party/blink/renderer/platform/wtf/hash_table.h b/third_party/blink/renderer/platform/wtf/hash_table.h
index 26173045..119f4ebb 100644
--- a/third_party/blink/renderer/platform/wtf/hash_table.h
+++ b/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -1667,10 +1667,7 @@
       }
     }
   }
-  // Notify if this is a weak table since immediately freeing a weak hash table
-  // backing may cause a use-after-free when the weak callback is called.
-  Allocator::FreeHashTableBacking(table,
-                                  Traits::kWeakHandlingFlag == kWeakHandling);
+  Allocator::FreeHashTableBacking(table);
 }
 
 template <typename Key,
diff --git a/third_party/fuchsia-sdk/BUILD.gn b/third_party/fuchsia-sdk/BUILD.gn
index 0cf8012..a355f4a5 100644
--- a/third_party/fuchsia-sdk/BUILD.gn
+++ b/third_party/fuchsia-sdk/BUILD.gn
@@ -209,7 +209,7 @@
   namespace = "fuchsia"
   namespace_path = "fuchsia"
   sources = [
-    "geometry.fidl",
+    "math.fidl",
   ]
 }
 
diff --git a/third_party/nvml/LICENSE b/third_party/nvml/LICENSE
new file mode 100644
index 0000000..030bfc1
--- /dev/null
+++ b/third_party/nvml/LICENSE
@@ -0,0 +1,33 @@
+
+Copyright 1993-2017 NVIDIA Corporation.  All rights reserved.
+
+NOTICE TO USER:
+
+This source code is subject to NVIDIA ownership rights under U.S. and
+international Copyright laws.  Users and possessors of this source code
+are hereby granted a nonexclusive, royalty-free license to use this code
+in individual and commercial software.
+
+NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
+CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
+IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
+OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS,  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION,  ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THIS SOURCE CODE.
+
+U.S. Government End Users.   This source code is a "commercial item" as
+that term is defined at  48 C.F.R. 2.101 (OCT 1995), consisting  of
+"commercial computer  software"  and "commercial computer software
+documentation" as such terms are  used in 48 C.F.R. 12.212 (SEPT 1995)
+and is provided to the U.S. Government only as a commercial end item.
+Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
+227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
+source code with only those rights set forth herein.
+
+Any use of this source code in individual and commercial software must
+include, in the user documentation and internal comments to the code,
+the above Disclaimer and U.S. Government End Users Notice.
diff --git a/third_party/nvml/OWNERS b/third_party/nvml/OWNERS
new file mode 100644
index 0000000..84f8217
--- /dev/null
+++ b/third_party/nvml/OWNERS
@@ -0,0 +1,2 @@
+kbr@chromium.org
+zmo@chromium.org
diff --git a/third_party/nvml/README.chromium b/third_party/nvml/README.chromium
new file mode 100644
index 0000000..5d62575
--- /dev/null
+++ b/third_party/nvml/README.chromium
@@ -0,0 +1,20 @@
+Name: NVIDIA Management Library
+Short Name: nvml
+URL: https://developer.nvidia.com/nvidia-management-library-nvml
+Version: 9.1.85
+License: NVML license
+License File: LICENSE
+Security Critical: yes
+
+Description:
+This is a header file for interfacing with the NVML library that ships as a part
+of NVIDIA proprietary drivers on Windows. The library can be used to query GPU
+hardware and GPU driver information. Chromium loads the NVML library dynamically
+and uses it for whitelisting and blacklisting purposes on Windows.
+
+Points of contact at NVIDIA:
+oetuaho@nvidia.com
+amalp@nvidia.com
+
+Local Modifications:
+Trailing whitespace has been trimmed from the header file.
diff --git a/third_party/nvml/nvml.h b/third_party/nvml/nvml.h
new file mode 100644
index 0000000..8e960db
--- /dev/null
+++ b/third_party/nvml/nvml.h
@@ -0,0 +1,5684 @@
+/*
+ * Copyright 1993-2017 NVIDIA Corporation.  All rights reserved.
+ *
+ * NOTICE TO USER:
+ *
+ * This source code is subject to NVIDIA ownership rights under U.S. and
+ * international Copyright laws.  Users and possessors of this source code
+ * are hereby granted a nonexclusive, royalty-free license to use this code
+ * in individual and commercial software.
+ *
+ * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
+ * CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
+ * IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
+ * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS,  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION,  ARISING OUT OF OR IN CONNECTION WITH THE USE
+ * OR PERFORMANCE OF THIS SOURCE CODE.
+ *
+ * U.S. Government End Users.   This source code is a "commercial item" as
+ * that term is defined at  48 C.F.R. 2.101 (OCT 1995), consisting  of
+ * "commercial computer  software"  and "commercial computer software
+ * documentation" as such terms are  used in 48 C.F.R. 12.212 (SEPT 1995)
+ * and is provided to the U.S. Government only as a commercial end item.
+ * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
+ * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
+ * source code with only those rights set forth herein.
+ *
+ * Any use of this source code in individual and commercial software must
+ * include, in the user documentation and internal comments to the code,
+ * the above Disclaimer and U.S. Government End Users Notice.
+ */
+
+/*
+NVML API Reference
+
+The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and
+managing various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building
+3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi
+tool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads.
+
+API Documentation
+
+Supported platforms:
+- Windows:     Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit
+- Linux:       32-bit and 64-bit
+- Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5
+
+Supported products:
+- Full Support
+    - All Tesla products, starting with the Fermi architecture
+    - All Quadro products, starting with the Fermi architecture
+    - All GRID products, starting with the Kepler architecture
+    - Selected GeForce Titan products
+- Limited Support
+    - All Geforce products, starting with the Fermi architecture
+
+The NVML library can be found at \%ProgramW6432\%\\"NVIDIA Corporation"\\NVSMI\\ on Windows. It is
+not be added to the system path by default. To dynamically link to NVML, add this path to the PATH
+environmental variable. To dynamically load NVML, call LoadLibrary with this path.
+
+On Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit
+and 64 bit NVML libraries will be installed.
+
+Online documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html
+*/
+
+#ifndef __nvml_nvml_h__
+#define __nvml_nvml_h__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * On Windows, set up methods for DLL export
+ * define NVML_STATIC_IMPORT when using nvml_loader library
+ */
+#if defined _WINDOWS
+    #if !defined NVML_STATIC_IMPORT
+        #if defined NVML_LIB_EXPORT
+            #define DECLDIR __declspec(dllexport)
+        #else
+            #define DECLDIR __declspec(dllimport)
+        #endif
+    #else
+        #define DECLDIR
+    #endif
+#else
+    #define DECLDIR
+#endif
+
+/**
+ * NVML API versioning support
+ */
+#define NVML_API_VERSION            9
+#define NVML_API_VERSION_STR        "9"
+#define nvmlInit                    nvmlInit_v2
+#define nvmlDeviceGetPciInfo        nvmlDeviceGetPciInfo_v3
+#define nvmlDeviceGetCount          nvmlDeviceGetCount_v2
+#define nvmlDeviceGetHandleByIndex  nvmlDeviceGetHandleByIndex_v2
+#define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2
+#define nvmlDeviceGetNvLinkRemotePciInfo nvmlDeviceGetNvLinkRemotePciInfo_v2
+
+/***************************************************************************************************/
+/** @defgroup nvmlDeviceStructs Device Structs
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Special constant that some fields take when they are not available.
+ * Used when only part of the struct is not available.
+ *
+ * Each structure explicitly states when to check for this value.
+ */
+#define NVML_VALUE_NOT_AVAILABLE (-1)
+
+typedef struct nvmlDevice_st* nvmlDevice_t;
+
+/**
+ * Buffer size guaranteed to be large enough for pci bus id
+ */
+#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE      32
+
+/**
+ * Buffer size guaranteed to be large enough for pci bus id for ::busIdLegacy
+ */
+#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE   16
+
+/**
+ * PCI information about a GPU device.
+ */
+typedef struct nvmlPciInfo_st
+{
+    char busIdLegacy[NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE]; //!< The legacy tuple domain:bus:device.function PCI identifier (&amp; NULL terminator)
+    unsigned int domain;             //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff
+    unsigned int bus;                //!< The bus on which the device resides, 0 to 0xff
+    unsigned int device;             //!< The device's id on the bus, 0 to 31
+    unsigned int pciDeviceId;        //!< The combined 16-bit device id and 16-bit vendor id
+
+    // Added in NVML 2.285 API
+    unsigned int pciSubSystemId;     //!< The 32-bit Sub System Device ID
+
+    char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (&amp; NULL terminator)
+} nvmlPciInfo_t;
+
+/**
+ * Detailed ECC error counts for a device.
+ *
+ * @deprecated  Different GPU families can have different memory error counters
+ *              See \ref nvmlDeviceGetMemoryErrorCounter
+ */
+typedef struct nvmlEccErrorCounts_st
+{
+    unsigned long long l1Cache;      //!< L1 cache errors
+    unsigned long long l2Cache;      //!< L2 cache errors
+    unsigned long long deviceMemory; //!< Device memory errors
+    unsigned long long registerFile; //!< Register file errors
+} nvmlEccErrorCounts_t;
+
+/**
+ * Utilization information for a device.
+ * Each sample period may be between 1 second and 1/6 second, depending on the product being queried.
+ */
+typedef struct nvmlUtilization_st
+{
+    unsigned int gpu;                //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU
+    unsigned int memory;             //!< Percent of time over the past sample period during which global (device) memory was being read or written
+} nvmlUtilization_t;
+
+/**
+ * Memory allocation information for a device.
+ */
+typedef struct nvmlMemory_st
+{
+    unsigned long long total;        //!< Total installed FB memory (in bytes)
+    unsigned long long free;         //!< Unallocated FB memory (in bytes)
+    unsigned long long used;         //!< Allocated FB memory (in bytes). Note that the driver/GPU always sets aside a small amount of memory for bookkeeping
+} nvmlMemory_t;
+
+/**
+ * BAR1 Memory allocation Information for a device
+ */
+typedef struct nvmlBAR1Memory_st
+{
+    unsigned long long bar1Total;    //!< Total BAR1 Memory (in bytes)
+    unsigned long long bar1Free;     //!< Unallocated BAR1 Memory (in bytes)
+    unsigned long long bar1Used;     //!< Allocated Used Memory (in bytes)
+}nvmlBAR1Memory_t;
+
+/**
+ * Information about running compute processes on the GPU
+ */
+typedef struct nvmlProcessInfo_st
+{
+    unsigned int pid;                 //!< Process ID
+    unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes.
+                                      //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported
+                                      //! because Windows KMD manages all the memory and not the NVIDIA driver
+} nvmlProcessInfo_t;
+
+/**
+ * Enum to represent type of bridge chip
+ */
+typedef enum nvmlBridgeChipType_enum
+{
+    NVML_BRIDGE_CHIP_PLX = 0,
+    NVML_BRIDGE_CHIP_BRO4 = 1
+}nvmlBridgeChipType_t;
+
+/**
+ * Maximum number of NvLink links supported
+ */
+#define NVML_NVLINK_MAX_LINKS 6
+
+/**
+ * Enum to represent the NvLink utilization counter packet units
+ */
+typedef enum nvmlNvLinkUtilizationCountUnits_enum
+{
+    NVML_NVLINK_COUNTER_UNIT_CYCLES =  0,     // count by cycles
+    NVML_NVLINK_COUNTER_UNIT_PACKETS = 1,     // count by packets
+    NVML_NVLINK_COUNTER_UNIT_BYTES   = 2,     // count by bytes
+
+    // this must be last
+    NVML_NVLINK_COUNTER_UNIT_COUNT
+} nvmlNvLinkUtilizationCountUnits_t;
+
+/**
+ * Enum to represent the NvLink utilization counter packet types to count
+ *  ** this is ONLY applicable with the units as packets or bytes
+ *  ** as specified in \a nvmlNvLinkUtilizationCountUnits_t
+ *  ** all packet filter descriptions are target GPU centric
+ *  ** these can be "OR'd" together
+ */
+typedef enum nvmlNvLinkUtilizationCountPktTypes_enum
+{
+    NVML_NVLINK_COUNTER_PKTFILTER_NOP        = 0x1,     // no operation packets
+    NVML_NVLINK_COUNTER_PKTFILTER_READ       = 0x2,     // read packets
+    NVML_NVLINK_COUNTER_PKTFILTER_WRITE      = 0x4,     // write packets
+    NVML_NVLINK_COUNTER_PKTFILTER_RATOM      = 0x8,     // reduction atomic requests
+    NVML_NVLINK_COUNTER_PKTFILTER_NRATOM     = 0x10,    // non-reduction atomic requests
+    NVML_NVLINK_COUNTER_PKTFILTER_FLUSH      = 0x20,    // flush requests
+    NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA   = 0x40,    // responses with data
+    NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80,    // responses without data
+    NVML_NVLINK_COUNTER_PKTFILTER_ALL        = 0xFF     // all packets
+} nvmlNvLinkUtilizationCountPktTypes_t;
+
+/**
+ * Struct to define the NVLINK counter controls
+ */
+typedef struct nvmlNvLinkUtilizationControl_st
+{
+    nvmlNvLinkUtilizationCountUnits_t units;
+    nvmlNvLinkUtilizationCountPktTypes_t pktfilter;
+} nvmlNvLinkUtilizationControl_t;
+
+/**
+ * Enum to represent NvLink queryable capabilities
+ */
+typedef enum nvmlNvLinkCapability_enum
+{
+    NVML_NVLINK_CAP_P2P_SUPPORTED = 0,     // P2P over NVLink is supported
+    NVML_NVLINK_CAP_SYSMEM_ACCESS = 1,     // Access to system memory is supported
+    NVML_NVLINK_CAP_P2P_ATOMICS   = 2,     // P2P atomics are supported
+    NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3,     // System memory atomics are supported
+    NVML_NVLINK_CAP_SLI_BRIDGE    = 4,     // SLI is supported over this link
+    NVML_NVLINK_CAP_VALID         = 5,     // Link is supported on this device
+    // should be last
+    NVML_NVLINK_CAP_COUNT
+} nvmlNvLinkCapability_t;
+
+/**
+ * Enum to represent NvLink queryable error counters
+ */
+typedef enum nvmlNvLinkErrorCounter_enum
+{
+    NVML_NVLINK_ERROR_DL_REPLAY   = 0,     // Data link transmit replay error counter
+    NVML_NVLINK_ERROR_DL_RECOVERY = 1,     // Data link transmit recovery error counter
+    NVML_NVLINK_ERROR_DL_CRC_FLIT = 2,     // Data link receive flow control digit CRC error counter
+    NVML_NVLINK_ERROR_DL_CRC_DATA = 3,     // Data link receive data CRC error counter
+
+    // this must be last
+    NVML_NVLINK_ERROR_COUNT
+} nvmlNvLinkErrorCounter_t;
+
+/**
+ * Represents level relationships within a system between two GPUs
+ * The enums are spaced to allow for future relationships
+ */
+typedef enum nvmlGpuLevel_enum
+{
+    NVML_TOPOLOGY_INTERNAL           = 0, // e.g. Tesla K80
+    NVML_TOPOLOGY_SINGLE             = 10, // all devices that only need traverse a single PCIe switch
+    NVML_TOPOLOGY_MULTIPLE           = 20, // all devices that need not traverse a host bridge
+    NVML_TOPOLOGY_HOSTBRIDGE         = 30, // all devices that are connected to the same host bridge
+    NVML_TOPOLOGY_NODE               = 40, // all devices that are connected to the same NUMA node but possibly multiple host bridges
+    NVML_TOPOLOGY_SYSTEM             = 50, // all devices in the system
+
+    // there is purposefully no COUNT here because of the need for spacing above
+} nvmlGpuTopologyLevel_t;
+
+/* Compatibility for CPU->NODE renaming */
+#define NVML_TOPOLOGY_CPU NVML_TOPOLOGY_NODE
+
+/* P2P Capability Index Status*/
+typedef enum nvmlGpuP2PStatus_enum
+{
+    NVML_P2P_STATUS_OK     = 0,
+    NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED,
+    NVML_P2P_STATUS_GPU_NOT_SUPPORTED,
+    NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED,
+    NVML_P2P_STATUS_DISABLED_BY_REGKEY,
+    NVML_P2P_STATUS_NOT_SUPPORTED,
+    NVML_P2P_STATUS_UNKNOWN
+
+} nvmlGpuP2PStatus_t;
+
+/* P2P Capability Index*/
+typedef enum nvmlGpuP2PCapsIndex_enum
+{
+    NVML_P2P_CAPS_INDEX_READ = 0,
+    NVML_P2P_CAPS_INDEX_WRITE,
+    NVML_P2P_CAPS_INDEX_NVLINK,
+    NVML_P2P_CAPS_INDEX_ATOMICS,
+    NVML_P2P_CAPS_INDEX_PROP,
+    NVML_P2P_CAPS_INDEX_UNKNOWN
+}nvmlGpuP2PCapsIndex_t;
+
+/**
+ * Maximum limit on Physical Bridges per Board
+ */
+#define NVML_MAX_PHYSICAL_BRIDGE                         (128)
+
+/**
+ * Information about the Bridge Chip Firmware
+ */
+typedef struct nvmlBridgeChipInfo_st
+{
+    nvmlBridgeChipType_t type;                  //!< Type of Bridge Chip
+    unsigned int fwVersion;                     //!< Firmware Version. 0=Version is unavailable
+}nvmlBridgeChipInfo_t;
+
+/**
+ * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate
+ * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth.
+ */
+typedef struct nvmlBridgeChipHierarchy_st
+{
+    unsigned char  bridgeCount;                 //!< Number of Bridge Chips on the Board
+    nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board
+}nvmlBridgeChipHierarchy_t;
+
+/**
+ *  Represents Type of Sampling Event
+ */
+typedef enum nvmlSamplingType_enum
+{
+    NVML_TOTAL_POWER_SAMPLES        = 0, //!< To represent total power drawn by GPU
+    NVML_GPU_UTILIZATION_SAMPLES    = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU
+    NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written
+    NVML_ENC_UTILIZATION_SAMPLES    = 3, //!< To represent percent of time during which NVENC remains busy
+    NVML_DEC_UTILIZATION_SAMPLES    = 4, //!< To represent percent of time during which NVDEC remains busy
+    NVML_PROCESSOR_CLK_SAMPLES      = 5, //!< To represent processor clock samples
+    NVML_MEMORY_CLK_SAMPLES         = 6, //!< To represent memory clock samples
+
+    // Keep this last
+    NVML_SAMPLINGTYPE_COUNT
+}nvmlSamplingType_t;
+
+/**
+ * Represents the queryable PCIe utilization counters
+ */
+typedef enum nvmlPcieUtilCounter_enum
+{
+    NVML_PCIE_UTIL_TX_BYTES             = 0, // 1KB granularity
+    NVML_PCIE_UTIL_RX_BYTES             = 1, // 1KB granularity
+
+    // Keep this last
+    NVML_PCIE_UTIL_COUNT
+} nvmlPcieUtilCounter_t;
+
+/**
+ * Represents the type for sample value returned
+ */
+typedef enum nvmlValueType_enum
+{
+    NVML_VALUE_TYPE_DOUBLE = 0,
+    NVML_VALUE_TYPE_UNSIGNED_INT = 1,
+    NVML_VALUE_TYPE_UNSIGNED_LONG = 2,
+    NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3,
+    NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4,
+
+    // Keep this last
+    NVML_VALUE_TYPE_COUNT
+}nvmlValueType_t;
+
+
+/**
+ * Union to represent different types of Value
+ */
+typedef union nvmlValue_st
+{
+    double dVal;                    //!< If the value is double
+    unsigned int uiVal;             //!< If the value is unsigned int
+    unsigned long ulVal;            //!< If the value is unsigned long
+    unsigned long long ullVal;      //!< If the value is unsigned long long
+    signed long long sllVal;        //!< If the value is signed long long
+}nvmlValue_t;
+
+/**
+ * Information for Sample
+ */
+typedef struct nvmlSample_st
+{
+    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds
+    nvmlValue_t sampleValue;        //!< Sample Value
+}nvmlSample_t;
+
+/**
+ * Represents type of perf policy for which violation times can be queried
+ */
+typedef enum nvmlPerfPolicyType_enum
+{
+    NVML_PERF_POLICY_POWER = 0,              //!< How long did power violations cause the GPU to be below application clocks
+    NVML_PERF_POLICY_THERMAL = 1,            //!< How long did thermal violations cause the GPU to be below application clocks
+    NVML_PERF_POLICY_SYNC_BOOST = 2,         //!< How long did sync boost cause the GPU to be below application clocks
+    NVML_PERF_POLICY_BOARD_LIMIT = 3,        //!< How long did the board limit cause the GPU to be below application clocks
+    NVML_PERF_POLICY_LOW_UTILIZATION = 4,    //!< How long did low utilization cause the GPU to be below application clocks
+    NVML_PERF_POLICY_RELIABILITY = 5,        //!< How long did the board reliability limit cause the GPU to be below application clocks
+
+    NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10,  //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above)
+    NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks
+
+    // Keep this last
+    NVML_PERF_POLICY_COUNT
+}nvmlPerfPolicyType_t;
+
+/**
+ * Struct to hold perf policy violation status data
+ */
+typedef struct nvmlViolationTime_st
+{
+    unsigned long long referenceTime;  //!< referenceTime represents CPU timestamp in microseconds
+    unsigned long long violationTime;  //!< violationTime in Nanoseconds
+}nvmlViolationTime_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlDeviceEnumvs Device Enums
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Generic enable/disable enum.
+ */
+typedef enum nvmlEnableState_enum
+{
+    NVML_FEATURE_DISABLED    = 0,     //!< Feature disabled
+    NVML_FEATURE_ENABLED     = 1      //!< Feature enabled
+} nvmlEnableState_t;
+
+//! Generic flag used to specify the default behavior of some functions. See description of particular functions for details.
+#define nvmlFlagDefault     0x00
+//! Generic flag used to force some behavior. See description of particular functions for details.
+#define nvmlFlagForce       0x01
+
+/**
+ *  * The Brand of the GPU
+ *   */
+typedef enum nvmlBrandType_enum
+{
+    NVML_BRAND_UNKNOWN = 0,
+    NVML_BRAND_QUADRO  = 1,
+    NVML_BRAND_TESLA   = 2,
+    NVML_BRAND_NVS     = 3,
+    NVML_BRAND_GRID    = 4,
+    NVML_BRAND_GEFORCE = 5,
+
+    // Keep this last
+    NVML_BRAND_COUNT
+} nvmlBrandType_t;
+
+/**
+ * Temperature thresholds.
+ */
+typedef enum nvmlTemperatureThresholds_enum
+{
+    NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0,    // Temperature at which the GPU will shut down
+                                                // for HW protection
+    NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1,    // Temperature at which the GPU will begin HW slowdown
+    NVML_TEMPERATURE_THRESHOLD_MEM_MAX  = 2,    // Memory Temperature at which the GPU will begin SW slowdown
+    NVML_TEMPERATURE_THRESHOLD_GPU_MAX  = 3,    // GPU Temperature at which the GPU can be throttled below base clock
+    // Keep this last
+    NVML_TEMPERATURE_THRESHOLD_COUNT
+} nvmlTemperatureThresholds_t;
+
+/**
+ * Temperature sensors.
+ */
+typedef enum nvmlTemperatureSensors_enum
+{
+    NVML_TEMPERATURE_GPU      = 0,    //!< Temperature sensor for the GPU die
+
+    // Keep this last
+    NVML_TEMPERATURE_COUNT
+} nvmlTemperatureSensors_t;
+
+/**
+ * Compute mode.
+ *
+ * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0.
+ * Earlier CUDA versions supported a single exclusive mode,
+ * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond.
+ */
+typedef enum nvmlComputeMode_enum
+{
+    NVML_COMPUTEMODE_DEFAULT           = 0,  //!< Default compute mode -- multiple contexts per device
+    NVML_COMPUTEMODE_EXCLUSIVE_THREAD  = 1,  //!< Support Removed
+    NVML_COMPUTEMODE_PROHIBITED        = 2,  //!< Compute-prohibited mode -- no contexts per device
+    NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3,  //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time
+
+    // Keep this last
+    NVML_COMPUTEMODE_COUNT
+} nvmlComputeMode_t;
+
+/**
+ * ECC bit types.
+ *
+ * @deprecated See \ref nvmlMemoryErrorType_t for a more flexible type
+ */
+#define nvmlEccBitType_t nvmlMemoryErrorType_t
+
+/**
+ * Single bit ECC errors
+ *
+ * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_CORRECTED
+ */
+#define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED
+
+/**
+ * Double bit ECC errors
+ *
+ * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED
+ */
+#define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED
+
+/**
+ * Memory error types
+ */
+typedef enum nvmlMemoryErrorType_enum
+{
+    /**
+     * A memory error that was corrected
+     *
+     * For ECC errors, these are single bit errors
+     * For Texture memory, these are errors fixed by resend
+     */
+    NVML_MEMORY_ERROR_TYPE_CORRECTED = 0,
+    /**
+     * A memory error that was not corrected
+     *
+     * For ECC errors, these are double bit errors
+     * For Texture memory, these are errors where the resend fails
+     */
+    NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1,
+
+
+    // Keep this last
+    NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types
+
+} nvmlMemoryErrorType_t;
+
+/**
+ * ECC counter types.
+ *
+ * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent.
+ *       On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver
+ *       client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app
+ *       is run.
+ */
+typedef enum nvmlEccCounterType_enum
+{
+    NVML_VOLATILE_ECC      = 0,      //!< Volatile counts are reset each time the driver loads.
+    NVML_AGGREGATE_ECC     = 1,      //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device)
+
+    // Keep this last
+    NVML_ECC_COUNTER_TYPE_COUNT      //!< Count of memory counter types
+} nvmlEccCounterType_t;
+
+/**
+ * Clock types.
+ *
+ * All speeds are in Mhz.
+ */
+typedef enum nvmlClockType_enum
+{
+    NVML_CLOCK_GRAPHICS  = 0,        //!< Graphics clock domain
+    NVML_CLOCK_SM        = 1,        //!< SM clock domain
+    NVML_CLOCK_MEM       = 2,        //!< Memory clock domain
+    NVML_CLOCK_VIDEO     = 3,        //!< Video encoder/decoder clock domain
+
+    // Keep this last
+    NVML_CLOCK_COUNT //<! Count of clock types
+} nvmlClockType_t;
+
+/**
+ * Clock Ids.  These are used in combination with nvmlClockType_t
+ * to specify a single clock value.
+ */
+typedef enum nvmlClockId_enum
+{
+    NVML_CLOCK_ID_CURRENT            = 0,   //!< Current actual clock value
+    NVML_CLOCK_ID_APP_CLOCK_TARGET   = 1,   //!< Target application clock
+    NVML_CLOCK_ID_APP_CLOCK_DEFAULT  = 2,   //!< Default application clock target
+    NVML_CLOCK_ID_CUSTOMER_BOOST_MAX = 3,   //!< OEM-defined maximum clock rate
+
+    //Keep this last
+    NVML_CLOCK_ID_COUNT //<! Count of Clock Ids.
+} nvmlClockId_t;
+
+/**
+ * Driver models.
+ *
+ * Windows only.
+ */
+typedef enum nvmlDriverModel_enum
+{
+    NVML_DRIVER_WDDM      = 0,       //!< WDDM driver model -- GPU treated as a display device
+    NVML_DRIVER_WDM       = 1        //!< WDM (TCC) model (recommended) -- GPU treated as a generic device
+} nvmlDriverModel_t;
+
+/**
+ * Allowed PStates.
+ */
+typedef enum nvmlPStates_enum
+{
+    NVML_PSTATE_0               = 0,       //!< Performance state 0 -- Maximum Performance
+    NVML_PSTATE_1               = 1,       //!< Performance state 1
+    NVML_PSTATE_2               = 2,       //!< Performance state 2
+    NVML_PSTATE_3               = 3,       //!< Performance state 3
+    NVML_PSTATE_4               = 4,       //!< Performance state 4
+    NVML_PSTATE_5               = 5,       //!< Performance state 5
+    NVML_PSTATE_6               = 6,       //!< Performance state 6
+    NVML_PSTATE_7               = 7,       //!< Performance state 7
+    NVML_PSTATE_8               = 8,       //!< Performance state 8
+    NVML_PSTATE_9               = 9,       //!< Performance state 9
+    NVML_PSTATE_10              = 10,      //!< Performance state 10
+    NVML_PSTATE_11              = 11,      //!< Performance state 11
+    NVML_PSTATE_12              = 12,      //!< Performance state 12
+    NVML_PSTATE_13              = 13,      //!< Performance state 13
+    NVML_PSTATE_14              = 14,      //!< Performance state 14
+    NVML_PSTATE_15              = 15,      //!< Performance state 15 -- Minimum Performance
+    NVML_PSTATE_UNKNOWN         = 32       //!< Unknown performance state
+} nvmlPstates_t;
+
+/**
+ * GPU Operation Mode
+ *
+ * GOM allows to reduce power usage and optimize GPU throughput by disabling GPU features.
+ *
+ * Each GOM is designed to meet specific user needs.
+ */
+typedef enum nvmlGom_enum
+{
+    NVML_GOM_ALL_ON                    = 0, //!< Everything is enabled and running at full speed
+
+    NVML_GOM_COMPUTE                   = 1, //!< Designed for running only compute tasks. Graphics operations
+                                            //!< are not allowed
+
+    NVML_GOM_LOW_DP                    = 2  //!< Designed for running graphics applications that don't require
+                                            //!< high bandwidth double precision
+} nvmlGpuOperationMode_t;
+
+/**
+ * Available infoROM objects.
+ */
+typedef enum nvmlInforomObject_enum
+{
+    NVML_INFOROM_OEM            = 0,       //!< An object defined by OEM
+    NVML_INFOROM_ECC            = 1,       //!< The ECC object determining the level of ECC support
+    NVML_INFOROM_POWER          = 2,       //!< The power management object
+
+    // Keep this last
+    NVML_INFOROM_COUNT                     //!< This counts the number of infoROM objects the driver knows about
+} nvmlInforomObject_t;
+
+/**
+ * Return values for NVML API calls.
+ */
+typedef enum nvmlReturn_enum
+{
+    NVML_SUCCESS = 0,                   //!< The operation was successful
+    NVML_ERROR_UNINITIALIZED = 1,       //!< NVML was not first initialized with nvmlInit()
+    NVML_ERROR_INVALID_ARGUMENT = 2,    //!< A supplied argument is invalid
+    NVML_ERROR_NOT_SUPPORTED = 3,       //!< The requested operation is not available on target device
+    NVML_ERROR_NO_PERMISSION = 4,       //!< The current user does not have permission for operation
+    NVML_ERROR_ALREADY_INITIALIZED = 5, //!< Deprecated: Multiple initializations are now allowed through ref counting
+    NVML_ERROR_NOT_FOUND = 6,           //!< A query to find an object was unsuccessful
+    NVML_ERROR_INSUFFICIENT_SIZE = 7,   //!< An input argument is not large enough
+    NVML_ERROR_INSUFFICIENT_POWER = 8,  //!< A device's external power cables are not properly attached
+    NVML_ERROR_DRIVER_NOT_LOADED = 9,   //!< NVIDIA driver is not loaded
+    NVML_ERROR_TIMEOUT = 10,            //!< User provided timeout passed
+    NVML_ERROR_IRQ_ISSUE = 11,          //!< NVIDIA Kernel detected an interrupt issue with a GPU
+    NVML_ERROR_LIBRARY_NOT_FOUND = 12,  //!< NVML Shared Library couldn't be found or loaded
+    NVML_ERROR_FUNCTION_NOT_FOUND = 13, //!< Local version of NVML doesn't implement this function
+    NVML_ERROR_CORRUPTED_INFOROM = 14,  //!< infoROM is corrupted
+    NVML_ERROR_GPU_IS_LOST = 15,        //!< The GPU has fallen off the bus or has otherwise become inaccessible
+    NVML_ERROR_RESET_REQUIRED = 16,     //!< The GPU requires a reset before it can be used again
+    NVML_ERROR_OPERATING_SYSTEM = 17,   //!< The GPU control device has been blocked by the operating system/cgroups
+    NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18,   //!< RM detects a driver/library version mismatch
+    NVML_ERROR_IN_USE = 19,             //!< An operation cannot be performed because the GPU is currently in use
+    NVML_ERROR_MEMORY = 20,             //!< Insufficient memory
+    NVML_ERROR_NO_DATA = 21,            //!<No data
+    NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22,    //!< The requested vgpu operation is not available on target device, becasue ECC is enabled
+    NVML_ERROR_UNKNOWN = 999            //!< An internal driver error occurred
+} nvmlReturn_t;
+
+/**
+ * Memory locations
+ *
+ * See \ref nvmlDeviceGetMemoryErrorCounter
+ */
+typedef enum nvmlMemoryLocation_enum
+{
+    NVML_MEMORY_LOCATION_L1_CACHE = 0,       //!< GPU L1 Cache
+    NVML_MEMORY_LOCATION_L2_CACHE = 1,       //!< GPU L2 Cache
+    NVML_MEMORY_LOCATION_DEVICE_MEMORY = 2,  //!< GPU Device Memory
+    NVML_MEMORY_LOCATION_REGISTER_FILE = 3,  //!< GPU Register File
+    NVML_MEMORY_LOCATION_TEXTURE_MEMORY = 4, //!< GPU Texture Memory
+    NVML_MEMORY_LOCATION_TEXTURE_SHM    = 5, //!< Shared memory
+    NVML_MEMORY_LOCATION_CBU            = 6, //!< CBU
+
+    // Keep this last
+    NVML_MEMORY_LOCATION_COUNT              //!< This counts the number of memory locations the driver knows about
+} nvmlMemoryLocation_t;
+
+/**
+ * Causes for page retirement
+ */
+typedef enum nvmlPageRetirementCause_enum
+{
+    NVML_PAGE_RETIREMENT_CAUSE_MULTIPLE_SINGLE_BIT_ECC_ERRORS = 0, //!< Page was retired due to multiple single bit ECC error
+    NVML_PAGE_RETIREMENT_CAUSE_DOUBLE_BIT_ECC_ERROR = 1,           //!< Page was retired due to double bit ECC error
+
+    // Keep this last
+    NVML_PAGE_RETIREMENT_CAUSE_COUNT
+} nvmlPageRetirementCause_t;
+
+/**
+ * API types that allow changes to default permission restrictions
+ */
+typedef enum nvmlRestrictedAPI_enum
+{
+    NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS = 0,   //!< APIs that change application clocks, see nvmlDeviceSetApplicationsClocks
+                                                      //!< and see nvmlDeviceResetApplicationsClocks
+    NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS = 1,  //!< APIs that enable/disable Auto Boosted clocks
+                                                      //!< see nvmlDeviceSetAutoBoostedClocksEnabled
+    // Keep this last
+    NVML_RESTRICTED_API_COUNT
+} nvmlRestrictedAPI_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlGridEnums GRID Enums
+ *  @{
+ */
+/***************************************************************************************************/
+
+/*!
+ * GPU virtualization mode types.
+ */
+typedef enum nvmlGpuVirtualizationMode {
+    NVML_GPU_VIRTUALIZATION_MODE_NONE = 0,  //!< Represents Bare Metal GPU
+    NVML_GPU_VIRTUALIZATION_MODE_PASSTHROUGH = 1,  //!< Device is associated with GPU-Passthorugh
+    NVML_GPU_VIRTUALIZATION_MODE_VGPU = 2,  //!< Device is associated with vGPU inside virtual machine.
+    NVML_GPU_VIRTUALIZATION_MODE_HOST_VGPU = 3,  //!< Device is associated with VGX hypervisor in vGPU mode
+    NVML_GPU_VIRTUALIZATION_MODE_HOST_VSGA = 4,  //!< Device is associated with VGX hypervisor in vSGA mode
+} nvmlGpuVirtualizationMode_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlFieldValueEnums Field Value Enums
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Field Identifiers.
+ *
+ * All Identifiers pertain to a device. Each ID is only used once and is guaranteed never to change.
+ */
+#define NVML_FI_DEV_ECC_CURRENT           1   //!< Current ECC mode. 1=Active. 0=Inactive
+#define NVML_FI_DEV_ECC_PENDING           2   //!< Pending ECC mode. 1=Active. 0=Inactive
+/* ECC Count Totals */
+#define NVML_FI_DEV_ECC_SBE_VOL_TOTAL     3   //!< Total single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_TOTAL     4   //!< Total double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_TOTAL     5   //!< Total single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_TOTAL     6   //!< Total double bit aggregate (persistent) ECC errors
+/* Individual ECC locations */
+#define NVML_FI_DEV_ECC_SBE_VOL_L1        7   //!< L1 cache single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_L1        8   //!< L1 cache double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_VOL_L2        9   //!< L2 cache single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_L2        10  //!< L2 cache double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_VOL_DEV       11  //!< Device memory single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_DEV       12  //!< Device memory double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_VOL_REG       13  //!< Register file single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_REG       14  //!< Register file double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_VOL_TEX       15  //!< Texture memory single bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_TEX       16  //!< Texture memory double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_DBE_VOL_CBU       17  //!< CBU double bit volatile ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_L1        18  //!< L1 cache single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_L1        19  //!< L1 cache double bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_L2        20  //!< L2 cache single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_L2        21  //!< L2 cache double bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_DEV       22  //!< Device memory single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_DEV       23  //!< Device memory double bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_REG       24  //!< Register File single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_REG       25  //!< Register File double bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_SBE_AGG_TEX       26  //!< Texture memory single bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_TEX       27  //!< Texture memory double bit aggregate (persistent) ECC errors
+#define NVML_FI_DEV_ECC_DBE_AGG_CBU       28  //!< CBU double bit aggregate ECC errors
+
+/* Page Retirement */
+#define NVML_FI_DEV_RETIRED_SBE           29  //!< Number of retired pages because of single bit errors
+#define NVML_FI_DEV_RETIRED_DBE           30  //!< Number of retired pages because of double bit errors
+#define NVML_FI_DEV_RETIRED_PENDING       31  //!< If any pages are pending retirement. 1=yes. 0=no.
+
+/* NvLink Flit Error Counters */
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L0    32 //!< NVLink flow control CRC  Error Counter for Lane 0
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L1    33 //!< NVLink flow control CRC  Error Counter for Lane 1
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L2    34 //!< NVLink flow control CRC  Error Counter for Lane 2
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L3    35 //!< NVLink flow control CRC  Error Counter for Lane 3
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L4    36 //!< NVLink flow control CRC  Error Counter for Lane 4
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L5    37 //!< NVLink flow control CRC  Error Counter for Lane 5
+#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL 38 //!< NVLink flow control CRC  Error Counter total for all Lanes
+
+/* NvLink CRC Data Error Counters */
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L0    39 //!< NVLink data CRC Error Counter for Lane 0
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L1    40 //!< NVLink data CRC Error Counter for Lane 1
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L2    41 //!< NVLink data CRC Error Counter for Lane 2
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L3    42 //!< NVLink data CRC Error Counter for Lane 3
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L4    43 //!< NVLink data CRC Error Counter for Lane 4
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L5    44 //!< NVLink data CRC Error Counter for Lane 5
+#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL 45 //!< NvLink data CRC Error Counter total for all Lanes
+
+/* NvLink Replay Error Counters */
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L0      46 //!< NVLink Replay Error Counter for Lane 0
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L1      47 //!< NVLink Replay Error Counter for Lane 1
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L2      48 //!< NVLink Replay Error Counter for Lane 2
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L3      49 //!< NVLink Replay Error Counter for Lane 3
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L4      50 //!< NVLink Replay Error Counter for Lane 4
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L5      51 //!< NVLink Replay Error Counter for Lane 5
+#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL   52 //!< NVLink Replay Error Counter total for all Lanes
+
+/* NvLink Recovery Error Counters */
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L0    53 //!< NVLink Recovery Error Counter for Lane 0
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L1    54 //!< NVLink Recovery Error Counter for Lane 1
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L2    55 //!< NVLink Recovery Error Counter for Lane 2
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L3    56 //!< NVLink Recovery Error Counter for Lane 3
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L4    57 //!< NVLink Recovery Error Counter for Lane 4
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L5    58 //!< NVLink Recovery Error Counter for Lane 5
+#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL 59 //!< NVLink Recovery Error Counter total for all Lanes
+
+/* NvLink Bandwidth Counters */
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L0     60 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 0
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L1     61 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 1
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L2     62 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 2
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L3     63 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 3
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L4     64 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 4
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L5     65 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 5
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_TOTAL  66 //!< NVLink Bandwidth Counter Total for Counter Set 0, All Lanes
+
+/* NvLink Bandwidth Counters */
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L0     67 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 0
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L1     68 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 1
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L2     69 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 2
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L3     70 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 3
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L4     71 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 4
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L5     72 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 5
+#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_TOTAL  73 //!< NVLink Bandwidth Counter Total for Counter Set 1, All Lanes
+
+/* NVML Perf Policy Counters */
+#define NVML_FI_DEV_PERF_POLICY_POWER              74   //!< Perf Policy Counter for Power Policy
+#define NVML_FI_DEV_PERF_POLICY_THERMAL            75   //!< Perf Policy Counter for Thermal Policy
+#define NVML_FI_DEV_PERF_POLICY_SYNC_BOOST         76   //!< Perf Policy Counter for Sync boost Policy
+#define NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT        77   //!< Perf Policy Counter for Board Limit
+#define NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION    78   //!< Perf Policy Counter for Low GPU Utilization Policy
+#define NVML_FI_DEV_PERF_POLICY_RELIABILITY        79   //!< Perf Policy Counter for Reliability Policy
+#define NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS   80   //!< Perf Policy Counter for Total App Clock Policy
+#define NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS  81   //!< Perf Policy Counter for Total Base Clocks Policy
+
+/* Memory temperatures */
+#define NVML_FI_DEV_MEMORY_TEMP  82 //!< Memory temperature for the device
+
+/* Energy Counter */
+#define NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION 83 //!< Total energy consumption for the GPU in mJ since the driver was last reloaded
+
+/* NVLink Speed */
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L0     84  //!< NVLink Speed in MBps for Link 0
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L1     85  //!< NVLink Speed in MBps for Link 1
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L2     86  //!< NVLink Speed in MBps for Link 2
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L3     87  //!< NVLink Speed in MBps for Link 3
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L4     88  //!< NVLink Speed in MBps for Link 4
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L5     89  //!< NVLink Speed in MBps for Link 5
+#define NVML_FI_DEV_NVLINK_SPEED_MBPS_COMMON 90  //!< Common NVLink Speed in MBps for active links
+
+#define NVML_FI_DEV_NVLINK_LINK_COUNT        91  //!< Number of NVLinks present on the device
+
+#define NVML_FI_MAX 92 //!< One greater than the largest field ID defined above
+
+/**
+ * Information for a Field Value Sample
+ */
+typedef struct nvmlFieldValue_st
+{
+    unsigned int fieldId;       //!< ID of the NVML field to retrieve. This must be set before any call that uses this struct. See the constants starting with NVML_FI_ above.
+    unsigned int unused;        //!< Currently unused. This should be initialized to 0 by the caller before any API call
+    long long timestamp;        //!< CPU Timestamp of this value in microseconds since 1970
+    long long latencyUsec;      //!< How long this field value took to update (in usec) within NVML. This may be averaged across several fields that are serviced by the same driver call.
+    nvmlValueType_t valueType;  //!< Type of the value stored in value
+    nvmlReturn_t nvmlReturn;    //!< Return code for retrieving this value. This must be checked before looking at value, as value is undefined if nvmlReturn != NVML_SUCCESS
+    nvmlValue_t value;          //!< Value for this field. This is only valid if nvmlReturn == NVML_SUCCESS
+} nvmlFieldValue_t;
+
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlUnitStructs Unit Structs
+ *  @{
+ */
+/***************************************************************************************************/
+
+typedef struct nvmlUnit_st* nvmlUnit_t;
+
+/**
+ * Description of HWBC entry
+ */
+typedef struct nvmlHwbcEntry_st
+{
+    unsigned int hwbcId;
+    char firmwareVersion[32];
+} nvmlHwbcEntry_t;
+
+/**
+ * Fan state enum.
+ */
+typedef enum nvmlFanState_enum
+{
+    NVML_FAN_NORMAL       = 0,     //!< Fan is working properly
+    NVML_FAN_FAILED       = 1      //!< Fan has failed
+} nvmlFanState_t;
+
+/**
+ * Led color enum.
+ */
+typedef enum nvmlLedColor_enum
+{
+    NVML_LED_COLOR_GREEN       = 0,     //!< GREEN, indicates good health
+    NVML_LED_COLOR_AMBER       = 1      //!< AMBER, indicates problem
+} nvmlLedColor_t;
+
+
+/**
+ * LED states for an S-class unit.
+ */
+typedef struct nvmlLedState_st
+{
+    char cause[256];               //!< If amber, a text description of the cause
+    nvmlLedColor_t color;          //!< GREEN or AMBER
+} nvmlLedState_t;
+
+/**
+ * Static S-class unit info.
+ */
+typedef struct nvmlUnitInfo_st
+{
+    char name[96];                      //!< Product name
+    char id[96];                        //!< Product identifier
+    char serial[96];                    //!< Product serial number
+    char firmwareVersion[96];           //!< Firmware version
+} nvmlUnitInfo_t;
+
+/**
+ * Power usage information for an S-class unit.
+ * The power supply state is a human readable string that equals "Normal" or contains
+ * a combination of "Abnormal" plus one or more of the following:
+ *
+ *    - High voltage
+ *    - Fan failure
+ *    - Heatsink temperature
+ *    - Current limit
+ *    - Voltage below UV alarm threshold
+ *    - Low-voltage
+ *    - SI2C remote off command
+ *    - MOD_DISABLE input
+ *    - Short pin transition
+*/
+typedef struct nvmlPSUInfo_st
+{
+    char state[256];                 //!< The power supply state
+    unsigned int current;            //!< PSU current (A)
+    unsigned int voltage;            //!< PSU voltage (V)
+    unsigned int power;              //!< PSU power draw (W)
+} nvmlPSUInfo_t;
+
+/**
+ * Fan speed reading for a single fan in an S-class unit.
+ */
+typedef struct nvmlUnitFanInfo_st
+{
+    unsigned int speed;              //!< Fan speed (RPM)
+    nvmlFanState_t state;            //!< Flag that indicates whether fan is working properly
+} nvmlUnitFanInfo_t;
+
+/**
+ * Fan speed readings for an entire S-class unit.
+ */
+typedef struct nvmlUnitFanSpeeds_st
+{
+    nvmlUnitFanInfo_t fans[24];      //!< Fan speed data for each fan
+    unsigned int count;              //!< Number of fans in unit
+} nvmlUnitFanSpeeds_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @addtogroup nvmlEvents
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Handle to an event set
+ */
+typedef struct nvmlEventSet_st* nvmlEventSet_t;
+
+/** @defgroup nvmlEventType Event Types
+ * @{
+ * Event Types which user can be notified about.
+ * See description of particular functions for details.
+ *
+ * See \ref nvmlDeviceRegisterEvents and \ref nvmlDeviceGetSupportedEventTypes to check which devices
+ * support each event.
+ *
+ * Types can be combined with bitwise or operator '|' when passed to \ref nvmlDeviceRegisterEvents
+ */
+//! Event about single bit ECC errors
+/**
+ * \note A corrected texture memory error is not an ECC error, so it does not generate a single bit event
+ */
+#define nvmlEventTypeSingleBitEccError     0x0000000000000001LL
+
+//! Event about double bit ECC errors
+/**
+ * \note An uncorrected texture memory error is not an ECC error, so it does not generate a double bit event
+ */
+#define nvmlEventTypeDoubleBitEccError     0x0000000000000002LL
+
+//! Event about PState changes
+/**
+ *  \note On Fermi architecture PState changes are also an indicator that GPU is throttling down due to
+ *  no work being executed on the GPU, power capping or thermal capping. In a typical situation,
+ *  Fermi-based GPU should stay in P0 for the duration of the execution of the compute process.
+ */
+#define nvmlEventTypePState                0x0000000000000004LL
+
+//! Event that Xid critical error occurred
+#define nvmlEventTypeXidCriticalError      0x0000000000000008LL
+
+//! Event about clock changes
+/**
+ * Kepler only
+ */
+#define nvmlEventTypeClock                 0x0000000000000010LL
+
+//! Mask with no events
+#define nvmlEventTypeNone                  0x0000000000000000LL
+//! Mask of all events
+#define nvmlEventTypeAll (nvmlEventTypeNone    \
+        | nvmlEventTypeSingleBitEccError       \
+        | nvmlEventTypeDoubleBitEccError       \
+        | nvmlEventTypePState                  \
+        | nvmlEventTypeClock                   \
+        | nvmlEventTypeXidCriticalError        \
+        )
+/** @} */
+
+/**
+ * Information about occurred event
+ */
+typedef struct nvmlEventData_st
+{
+    nvmlDevice_t        device;         //!< Specific device where the event occurred
+    unsigned long long  eventType;      //!< Information about what specific event occurred
+    unsigned long long  eventData;      //!< Stores last XID error for the device in the event of nvmlEventTypeXidCriticalError,
+                                        //  eventData is 0 for any other event. eventData is set as 999 for unknown xid error.
+} nvmlEventData_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @addtogroup nvmlClocksThrottleReasons
+ *  @{
+ */
+/***************************************************************************************************/
+
+/** Nothing is running on the GPU and the clocks are dropping to Idle state
+ * \note This limiter may be removed in a later release
+ */
+#define nvmlClocksThrottleReasonGpuIdle                   0x0000000000000001LL
+
+/** GPU clocks are limited by current setting of applications clocks
+ *
+ * @see nvmlDeviceSetApplicationsClocks
+ * @see nvmlDeviceGetApplicationsClock
+ */
+#define nvmlClocksThrottleReasonApplicationsClocksSetting 0x0000000000000002LL
+
+/**
+ * @deprecated Renamed to \ref nvmlClocksThrottleReasonApplicationsClocksSetting
+ *             as the name describes the situation more accurately.
+ */
+#define nvmlClocksThrottleReasonUserDefinedClocks         nvmlClocksThrottleReasonApplicationsClocksSetting
+
+/** SW Power Scaling algorithm is reducing the clocks below requested clocks
+ *
+ * @see nvmlDeviceGetPowerUsage
+ * @see nvmlDeviceSetPowerManagementLimit
+ * @see nvmlDeviceGetPowerManagementLimit
+ */
+#define nvmlClocksThrottleReasonSwPowerCap                0x0000000000000004LL
+
+/** HW Slowdown (reducing the core clocks by a factor of 2 or more) is engaged
+ *
+ * This is an indicator of:
+ *   - temperature being too high
+ *   - External Power Brake Assertion is triggered (e.g. by the system power supply)
+ *   - Power draw is too high and Fast Trigger protection is reducing the clocks
+ *   - May be also reported during PState or clock change
+ *      - This behavior may be removed in a later release.
+ *
+ * @see nvmlDeviceGetTemperature
+ * @see nvmlDeviceGetTemperatureThreshold
+ * @see nvmlDeviceGetPowerUsage
+ */
+#define nvmlClocksThrottleReasonHwSlowdown                0x0000000000000008LL
+
+/** Sync Boost
+ *
+ * This GPU has been added to a Sync boost group with nvidia-smi or DCGM in
+ * order to maximize performance per watt. All GPUs in the sync boost group
+ * will boost to the minimum possible clocks across the entire group. Look at
+ * the throttle reasons for other GPUs in the system to see why those GPUs are
+ * holding this one at lower clocks.
+ *
+ */
+#define nvmlClocksThrottleReasonSyncBoost                 0x0000000000000010LL
+
+/** SW Thermal Slowdown
+ *
+ * This is an indicator of one or more of the following:
+ *  - Current GPU temperature above the GPU Max Operating Temperature
+ *  - Current memory temperature above the Memory Max Operating Temperature
+ *
+ */
+#define nvmlClocksThrottleReasonSwThermalSlowdown         0x0000000000000020LL
+
+/** HW Thermal Slowdown (reducing the core clocks by a factor of 2 or more) is engaged
+ *
+ * This is an indicator of:
+ *   - temperature being too high
+ *
+ * @see nvmlDeviceGetTemperature
+ * @see nvmlDeviceGetTemperatureThreshold
+ * @see nvmlDeviceGetPowerUsage
+ */
+#define nvmlClocksThrottleReasonHwThermalSlowdown         0x0000000000000040LL
+
+/** HW Power Brake Slowdown (reducing the core clocks by a factor of 2 or more) is engaged
+ *
+ * This is an indicator of:
+ *   - External Power Brake Assertion being triggered (e.g. by the system power supply)
+ *
+ * @see nvmlDeviceGetTemperature
+ * @see nvmlDeviceGetTemperatureThreshold
+ * @see nvmlDeviceGetPowerUsage
+ */
+#define nvmlClocksThrottleReasonHwPowerBrakeSlowdown      0x0000000000000080LL
+
+/** Bit mask representing no clocks throttling
+ *
+ * Clocks are as high as possible.
+ * */
+#define nvmlClocksThrottleReasonNone                      0x0000000000000000LL
+
+/** Bit mask representing all supported clocks throttling reasons
+ * New reasons might be added to this list in the future
+ */
+#define nvmlClocksThrottleReasonAll (nvmlClocksThrottleReasonNone \
+      | nvmlClocksThrottleReasonGpuIdle                           \
+      | nvmlClocksThrottleReasonApplicationsClocksSetting         \
+      | nvmlClocksThrottleReasonSwPowerCap                        \
+      | nvmlClocksThrottleReasonHwSlowdown                        \
+      | nvmlClocksThrottleReasonSyncBoost                         \
+      | nvmlClocksThrottleReasonSwThermalSlowdown                 \
+      | nvmlClocksThrottleReasonHwThermalSlowdown                 \
+      | nvmlClocksThrottleReasonHwPowerBrakeSlowdown              \
+)
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlAccountingStats Accounting Statistics
+ *  @{
+ *
+ *  Set of APIs designed to provide per process information about usage of GPU.
+ *
+ *  @note All accounting statistics and accounting mode live in nvidia driver and reset
+ *        to default (Disabled) when driver unloads.
+ *        It is advised to run with persistence mode enabled.
+ *
+ *  @note Enabling accounting mode has no negative impact on the GPU performance.
+ */
+/***************************************************************************************************/
+
+/**
+ * Describes accounting statistics of a process.
+ */
+typedef struct nvmlAccountingStats_st {
+    unsigned int gpuUtilization;                //!< Percent of time over the process's lifetime during which one or more kernels was executing on the GPU.
+                                                //! Utilization stats just like returned by \ref nvmlDeviceGetUtilizationRates but for the life time of a
+                                                //! process (not just the last sample period).
+                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlDeviceGetUtilizationRates is not supported
+
+    unsigned int memoryUtilization;             //!< Percent of time over the process's lifetime during which global (device) memory was being read or written.
+                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlDeviceGetUtilizationRates is not supported
+
+    unsigned long long maxMemoryUsage;          //!< Maximum total memory in bytes that was ever allocated by the process.
+                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlProcessInfo_t->usedGpuMemory is not supported
+
+
+    unsigned long long time;                    //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if
+                                                //!< the process is not terminated
+
+    unsigned long long startTime;               //!< CPU Timestamp in usec representing start time for the process
+
+    unsigned int isRunning;                     //!< Flag to represent if the process is running (1 for running, 0 for terminated)
+
+    unsigned int reserved[5];                   //!< Reserved for future use
+} nvmlAccountingStats_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlVgpuConstants Vgpu Constants
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlVgpuTypeGetLicense
+ */
+#define NVML_GRID_LICENSE_BUFFER_SIZE       128
+
+#define NVML_VGPU_NAME_BUFFER_SIZE          64
+
+#define NVML_MAX_VGPU_TYPES_PER_PGPU        17
+
+#define NVML_MAX_VGPU_INSTANCES_PER_PGPU    24
+
+#define NVML_GRID_LICENSE_FEATURE_MAX_COUNT 3
+
+#define NVML_GRID_LICENSE_INFO_MAX_LENGTH   128
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlVgpuEnum Vgpu Enum
+ *  @{
+ */
+/***************************************************************************************************/
+
+/*!
+ * Types of VM identifiers
+ */
+typedef enum nvmlVgpuVmIdType {
+    NVML_VGPU_VM_ID_DOMAIN_ID = 0, //!< VM ID represents DOMAIN ID
+    NVML_VGPU_VM_ID_UUID = 1,      //!< VM ID represents UUID
+} nvmlVgpuVmIdType_t;
+
+// vGPU GUEST info state.
+typedef enum nvmlVgpuGuestInfoState_enum
+{
+    NVML_VGPU_INSTANCE_GUEST_INFO_STATE_UNINITIALIZED = 0,  //<! Guest-dependent fields uninitialized
+    NVML_VGPU_INSTANCE_GUEST_INFO_STATE_INITIALIZED   = 1,  //<! Guest-dependent fields initialized
+} nvmlVgpuGuestInfoState_t;
+
+// GRID license feature code
+typedef enum {
+    NVML_GRID_LICENSE_FEATURE_CODE_VGPU = 1,         // Virtual GPU
+    NVML_GRID_LICENSE_FEATURE_CODE_VWORKSTATION = 2  // Virtual Workstation
+} nvmlGridLicenseFeatureCode_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlVgpuStructs Vgpu Structs
+ *  @{
+ */
+/***************************************************************************************************/
+
+typedef unsigned int nvmlVgpuTypeId_t;
+
+typedef unsigned int nvmlVgpuInstance_t;
+
+/**
+ * Structure to store Utilization Value and vgpuInstance
+ */
+typedef struct nvmlVgpuInstanceUtilizationSample_st
+{
+    nvmlVgpuInstance_t vgpuInstance;    //!< vGPU Instance
+    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds
+    nvmlValue_t smUtil;                 //!< SM (3D/Compute) Util Value
+    nvmlValue_t memUtil;                //!< Frame Buffer Memory Util Value
+    nvmlValue_t encUtil;                //!< Encoder Util Value
+    nvmlValue_t decUtil;                //!< Decoder Util Value
+} nvmlVgpuInstanceUtilizationSample_t;
+
+/**
+ * Structure to store Utilization Value, vgpuInstance and subprocess information
+ */
+typedef struct nvmlVgpuProcessUtilizationSample_st
+{
+    nvmlVgpuInstance_t vgpuInstance;                //!< vGPU Instance
+    unsigned int pid;                               //!< PID of process running within the vGPU VM
+    char processName[NVML_VGPU_NAME_BUFFER_SIZE];   //!< Name of process running within the vGPU VM
+    unsigned long long timeStamp;                   //!< CPU Timestamp in microseconds
+    unsigned int smUtil;                            //!< SM (3D/Compute) Util Value
+    unsigned int memUtil;                           //!< Frame Buffer Memory Util Value
+    unsigned int encUtil;                           //!< Encoder Util Value
+    unsigned int decUtil;                           //!< Decoder Util Value
+} nvmlVgpuProcessUtilizationSample_t;
+
+/**
+ * Structure to store utilization value and process Id
+ */
+typedef struct nvmlProcessUtilizationSample_st
+{
+    unsigned int pid;                   //!< PID of process
+    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds
+    unsigned int smUtil;                //!< SM (3D/Compute) Util Value
+    unsigned int memUtil;               //!< Frame Buffer Memory Util Value
+    unsigned int encUtil;               //!< Encoder Util Value
+    unsigned int decUtil;               //!< Decoder Util Value
+} nvmlProcessUtilizationSample_t;
+
+/**
+ * Structure to store GRID licensable features
+ */
+typedef struct nvmlGridLicensableFeature_st
+{
+    nvmlGridLicenseFeatureCode_t    featureCode;         //<! Licensed feature code
+    unsigned int                    featureState;        //<! Non-zero if feature is currently licensed, otherwise zero
+    char                            licenseInfo[NVML_GRID_LICENSE_INFO_MAX_LENGTH];
+} nvmlGridLicensableFeature_t;
+
+typedef struct nvmlGridLicensableFeatures_st
+{
+    int                         isGridLicenseSupported;     //<! Non-zero if GRID Software Licensing is supported on the system, otherwise zero
+    unsigned int                licensableFeaturesCount;    //<! Entries returned in \a gridLicensableFeatures array
+    nvmlGridLicensableFeature_t gridLicensableFeatures[NVML_GRID_LICENSE_FEATURE_MAX_COUNT];
+} nvmlGridLicensableFeatures_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlEncoderStructs Encoder Structs
+ *  @{
+ */
+/***************************************************************************************************/
+
+/*
+ * Represents type of encoder for capacity can be queried
+ */
+typedef enum nvmlEncoderQueryType_enum
+{
+    NVML_ENCODER_QUERY_H264 = 0,
+    NVML_ENCODER_QUERY_HEVC = 1,
+}nvmlEncoderType_t;
+
+/*
+ * Struct to hold encoder session data
+ */
+typedef struct nvmlEncoderSessionInfo_st
+{
+    unsigned int       sessionId;       //!< Unique session ID
+    unsigned int       pid;             //!< Owning process ID
+    nvmlVgpuInstance_t vgpuInstance;    //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero)
+    nvmlEncoderType_t  codecType;       //!< Video encoder type
+    unsigned int       hResolution;     //!< Current encode horizontal resolution
+    unsigned int       vResolution;     //!< Current encode vertical resolution
+    unsigned int       averageFps;      //!< Moving average encode frames per second
+    unsigned int       averageLatency;   //!< Moving average encode latency in microseconds
+}nvmlEncoderSessionInfo_t;
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlInitializationAndCleanup Initialization and Cleanup
+ * This chapter describes the methods that handle NVML initialization and cleanup.
+ * It is the user's responsibility to call \ref nvmlInit() before calling any other methods, and
+ * nvmlShutdown() once NVML is no longer being used.
+ *  @{
+ */
+/***************************************************************************************************/
+
+#define NVML_INIT_FLAG_NO_GPUS  1   //!< Don't fail nvmlInit() when no GPUs are found
+
+/**
+ * Initialize NVML, but don't initialize any GPUs yet.
+ *
+ * \note nvmlInit_v3 introduces a "flags" argument, that allows passing boolean values
+ *       modifying the behaviour of nvmlInit().
+ * \note In NVML 5.319 new nvmlInit_v2 has replaced nvmlInit"_v1" (default in NVML 4.304 and older) that
+ *       did initialize all GPU devices in the system.
+ *
+ * This allows NVML to communicate with a GPU
+ * when other GPUs in the system are unstable or in a bad state.  When using this API, GPUs are
+ * discovered and initialized in nvmlDeviceGetHandleBy* functions instead.
+ *
+ * \note To contrast nvmlInit_v2 with nvmlInit"_v1", NVML 4.304 nvmlInit"_v1" will fail when any detected GPU is in
+ *       a bad or unstable state.
+ *
+ * For all products.
+ *
+ * @param flags                                 behaviour modifier flags
+ *
+ * This method, should be called once before invoking any other methods in the library.
+ * A reference count of the number of initializations is maintained.  Shutdown only occurs
+ * when the reference count reaches zero.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                   if NVML has been properly initialized
+ *         - \ref NVML_ERROR_DRIVER_NOT_LOADED   if NVIDIA driver is not running
+ *         - \ref NVML_ERROR_NO_PERMISSION       if NVML does not have permission to talk to the driver
+ *         - \ref NVML_ERROR_UNKNOWN             on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlInit(void);
+
+/**
+ * nvmlInitWithFlags is a variant of nvmlInit(), that allows passing a set of boolean values
+ *       modifying the behaviour of nvmlInit().
+ *       Other than the "flags" parameter it is completely similar to \ref nvmlInit.
+ *
+ * For all products.
+ *
+ * @param flags                                 behaviour modifier flags
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                   if NVML has been properly initialized
+ *         - \ref NVML_ERROR_DRIVER_NOT_LOADED   if NVIDIA driver is not running
+ *         - \ref NVML_ERROR_NO_PERMISSION       if NVML does not have permission to talk to the driver
+ *         - \ref NVML_ERROR_UNKNOWN             on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlInitWithFlags(unsigned int flags);
+
+/**
+ * Shut down NVML by releasing all GPU resources previously allocated with \ref nvmlInit().
+ *
+ * For all products.
+ *
+ * This method should be called after NVML work is done, once for each call to \ref nvmlInit()
+ * A reference count of the number of initializations is maintained.  Shutdown only occurs
+ * when the reference count reaches zero.  For backwards compatibility, no error is reported if
+ * nvmlShutdown() is called more times than nvmlInit().
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if NVML has been properly shut down
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlShutdown(void);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlErrorReporting Error reporting
+ * This chapter describes helper functions for error reporting routines.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Helper method for converting NVML error codes into readable strings.
+ *
+ * For all products.
+ *
+ * @param result                               NVML error code to convert
+ *
+ * @return String representation of the error.
+ *
+ */
+const DECLDIR char* nvmlErrorString(nvmlReturn_t result);
+/** @} */
+
+
+/***************************************************************************************************/
+/** @defgroup nvmlConstants Constants
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetInforomVersion and \ref nvmlDeviceGetInforomImageVersion
+ */
+#define NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE       16
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetUUID
+ */
+#define NVML_DEVICE_UUID_BUFFER_SIZE                  80
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetBoardPartNumber
+ */
+#define NVML_DEVICE_PART_NUMBER_BUFFER_SIZE           80
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlSystemGetDriverVersion
+ */
+#define NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE        80
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlSystemGetNVMLVersion
+ */
+#define NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE          80
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetName
+ */
+#define NVML_DEVICE_NAME_BUFFER_SIZE                  64
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetSerial
+ */
+#define NVML_DEVICE_SERIAL_BUFFER_SIZE                30
+
+/**
+ * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetVbiosVersion
+ */
+#define NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE         32
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlSystemQueries System Queries
+ * This chapter describes the queries that NVML can perform against the local system. These queries
+ * are not device-specific.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Retrieves the version of the system's graphics driver.
+ *
+ * For all products.
+ *
+ * The version identifier is an alphanumeric string.  It will not exceed 80 characters in length
+ * (including the NULL terminator).  See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE.
+ *
+ * @param version                              Reference in which to return the version identifier
+ * @param length                               The maximum allowed length of the string returned in \a version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a version is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetDriverVersion(char *version, unsigned int length);
+
+/**
+ * Retrieves the version of the NVML library.
+ *
+ * For all products.
+ *
+ * The version identifier is an alphanumeric string.  It will not exceed 80 characters in length
+ * (including the NULL terminator).  See \ref nvmlConstants::NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE.
+ *
+ * @param version                              Reference in which to return the version identifier
+ * @param length                               The maximum allowed length of the string returned in \a version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a version is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetNVMLVersion(char *version, unsigned int length);
+
+/**
+ * Retrieves the version of the CUDA driver.
+ *
+ * For all products.
+ *
+ * The returned CUDA driver version is the same as the CUDA API
+ * cuDriverGetVersion() would return on the system.
+ *
+ * @param cudaDriverVersion                    Reference in which to return the version identifier
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a cudaDriverVersion has been set
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a cudaDriverVersion is NULL
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion(int *cudaDriverVersion);
+
+/**
+ * Gets name of the process with provided process id
+ *
+ * For all products.
+ *
+ * Returned process name is cropped to provided length.
+ * name string is encoded in ANSI.
+ *
+ * @param pid                                  The identifier of the process
+ * @param name                                 Reference in which to return the process name
+ * @param length                               The maximum allowed length of the string returned in \a name
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a name has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a name is NULL or \a length is 0.
+ *         - \ref NVML_ERROR_NOT_FOUND         if process doesn't exists
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetProcessName(unsigned int pid, char *name, unsigned int length);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlUnitQueries Unit Queries
+ * This chapter describes that queries that NVML can perform against each unit. For S-class systems only.
+ * In each case the device is identified with an nvmlUnit_t handle. This handle is obtained by
+ * calling \ref nvmlUnitGetHandleByIndex().
+ *  @{
+ */
+/***************************************************************************************************/
+
+ /**
+ * Retrieves the number of units in the system.
+ *
+ * For S-class products.
+ *
+ * @param unitCount                            Reference in which to return the number of units
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a unitCount has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unitCount is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetCount(unsigned int *unitCount);
+
+/**
+ * Acquire the handle for a particular unit, based on its index.
+ *
+ * For S-class products.
+ *
+ * Valid indices are derived from the \a unitCount returned by \ref nvmlUnitGetCount().
+ *   For example, if \a unitCount is 2 the valid indices are 0 and 1, corresponding to UNIT 0 and UNIT 1.
+ *
+ * The order in which NVML enumerates units has no guarantees of consistency between reboots.
+ *
+ * @param index                                The index of the target unit, >= 0 and < \a unitCount
+ * @param unit                                 Reference in which to return the unit handle
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a unit has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a index is invalid or \a unit is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit);
+
+/**
+ * Retrieves the static information associated with a unit.
+ *
+ * For S-class products.
+ *
+ * See \ref nvmlUnitInfo_t for details on available unit info.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param info                                 Reference in which to return the unit information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a info has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit is invalid or \a info is NULL
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info);
+
+/**
+ * Retrieves the LED state associated with this unit.
+ *
+ * For S-class products.
+ *
+ * See \ref nvmlLedState_t for details on allowed states.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param state                                Reference in which to return the current LED state
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a state has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit is invalid or \a state is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlUnitSetLedState()
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state);
+
+/**
+ * Retrieves the PSU stats for the unit.
+ *
+ * For S-class products.
+ *
+ * See \ref nvmlPSUInfo_t for details on available PSU info.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param psu                                  Reference in which to return the PSU information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a psu has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit is invalid or \a psu is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu);
+
+/**
+ * Retrieves the temperature readings for the unit, in degrees C.
+ *
+ * For S-class products.
+ *
+ * Depending on the product, readings may be available for intake (type=0),
+ * exhaust (type=1) and board (type=2).
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param type                                 The type of reading to take
+ * @param temp                                 Reference in which to return the intake temperature
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a temp has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit or \a type is invalid or \a temp is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp);
+
+/**
+ * Retrieves the fan speed readings for the unit.
+ *
+ * For S-class products.
+ *
+ * See \ref nvmlUnitFanSpeeds_t for details on available fan speed info.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param fanSpeeds                            Reference in which to return the fan speed information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a fanSpeeds has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit is invalid or \a fanSpeeds is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds);
+
+/**
+ * Retrieves the set of GPU devices that are attached to the specified unit.
+ *
+ * For S-class products.
+ *
+ * The \a deviceCount argument is expected to be set to the size of the input \a devices array.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param deviceCount                          Reference in which to provide the \a devices array size, and
+ *                                             to return the number of attached GPU devices
+ * @param devices                              Reference in which to return the references to the attached GPU devices
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a deviceCount and \a devices have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a deviceCount indicates that the \a devices array is too small
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit is invalid, either of \a deviceCount or \a devices is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices);
+
+/**
+ * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system.
+ *
+ * For S-class products.
+ *
+ * The \a hwbcCount argument is expected to be set to the size of the input \a hwbcEntries array.
+ * The HIC must be connected to an S-class system for it to be reported by this function.
+ *
+ * @param hwbcCount                            Size of hwbcEntries array
+ * @param hwbcEntries                          Array holding information about hwbc
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a hwbcCount and \a hwbcEntries have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if either \a hwbcCount or \a hwbcEntries is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a hwbcCount indicates that the \a hwbcEntries array is too small
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries);
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlDeviceQueries Device Queries
+ * This chapter describes that queries that NVML can perform against each device.
+ * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by
+ * calling one of \ref nvmlDeviceGetHandleByIndex(), \ref nvmlDeviceGetHandleBySerial(),
+ * \ref nvmlDeviceGetHandleByPciBusId(). or \ref nvmlDeviceGetHandleByUUID().
+ *  @{
+ */
+/***************************************************************************************************/
+
+ /**
+ * Retrieves the number of compute devices in the system. A compute device is a single GPU.
+ *
+ * For all products.
+ *
+ * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system
+ *       even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device.
+ *       Update your code to handle this error, or use NVML 4.304 or older nvml header file.
+ *       For backward binary compatibility reasons _v1 version of the API is still present in the shared
+ *       library.
+ *       Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to.
+ *
+ * @param deviceCount                          Reference in which to return the number of accessible devices
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a deviceCount has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a deviceCount is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount);
+
+/**
+ * Acquire the handle for a particular device, based on its index.
+ *
+ * For all products.
+ *
+ * Valid indices are derived from the \a accessibleDevices count returned by
+ *   \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices
+ *   are 0 and 1, corresponding to GPU 0 and GPU 1.
+ *
+ * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it
+ *   is recommended that devices be looked up by their PCI ids or UUID. See
+ *   \ref nvmlDeviceGetHandleByUUID() and \ref nvmlDeviceGetHandleByPciBusId().
+ *
+ * Note: The NVML index may not correlate with other APIs, such as the CUDA device index.
+ *
+ * Starting from NVML 5, this API causes NVML to initialize the target GPU
+ * NVML may initialize additional GPUs if:
+ *  - The target GPU is an SLI slave
+ *
+ * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system
+ *       even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device.
+ *       Update your code to handle this error, or use NVML 4.304 or older nvml header file.
+ *       For backward binary compatibility reasons _v1 version of the API is still present in the shared
+ *       library.
+ *       Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to.
+ *
+ *       This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index.
+ *       If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't
+ *       need to worry about that.
+ *
+ * @param index                                The index of the target GPU, >= 0 and < \a accessibleDevices
+ * @param device                               Reference in which to return the device handle
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a device has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a index is invalid or \a device is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables
+ *         - \ref NVML_ERROR_NO_PERMISSION      if the user doesn't have permission to talk to this device
+ *         - \ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ *
+ * @see nvmlDeviceGetIndex
+ * @see nvmlDeviceGetCount
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device);
+
+/**
+ * Acquire the handle for a particular device, based on its board serial number.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * This number corresponds to the value printed directly on the board, and to the value returned by
+ *   \ref nvmlDeviceGetSerial().
+ *
+ * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor
+ *             of \ref nvmlDeviceGetHandleByUUID.
+ *             For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT.
+ *
+ * Starting from NVML 5, this API causes NVML to initialize the target GPU
+ * NVML may initialize additional GPUs as it searches for the target GPU
+ *
+ * @param serial                               The board serial number of the target GPU
+ * @param device                               Reference in which to return the device handle
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a device has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a serial is invalid, \a device is NULL or more than one
+ *                                              device has the same serial (dual GPU boards)
+ *         - \ref NVML_ERROR_NOT_FOUND          if \a serial does not match a valid device on the system
+ *         - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables
+ *         - \ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if any GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ *
+ * @see nvmlDeviceGetSerial
+ * @see nvmlDeviceGetHandleByUUID
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device);
+
+/**
+ * Acquire the handle for a particular device, based on its globally unique immutable UUID associated with each device.
+ *
+ * For all products.
+ *
+ * @param uuid                                 The UUID of the target GPU
+ * @param device                               Reference in which to return the device handle
+ *
+ * Starting from NVML 5, this API causes NVML to initialize the target GPU
+ * NVML may initialize additional GPUs as it searches for the target GPU
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a device has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a uuid is invalid or \a device is null
+ *         - \ref NVML_ERROR_NOT_FOUND          if \a uuid does not match a valid device on the system
+ *         - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables
+ *         - \ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if any GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ *
+ * @see nvmlDeviceGetUUID
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device);
+
+/**
+ * Acquire the handle for a particular device, based on its PCI bus id.
+ *
+ * For all products.
+ *
+ * This value corresponds to the nvmlPciInfo_t::busId returned by \ref nvmlDeviceGetPciInfo().
+ *
+ * Starting from NVML 5, this API causes NVML to initialize the target GPU
+ * NVML may initialize additional GPUs if:
+ *  - The target GPU is an SLI slave
+ *
+ * \note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId"_v1" returns NVML_ERROR_NOT_FOUND
+ *       instead of NVML_ERROR_NO_PERMISSION.
+ *
+ * @param pciBusId                             The PCI bus id of the target GPU
+ * @param device                               Reference in which to return the device handle
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a device has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a pciBusId is invalid or \a device is NULL
+ *         - \ref NVML_ERROR_NOT_FOUND          if \a pciBusId does not match a valid device on the system
+ *         - \ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables
+ *         - \ref NVML_ERROR_NO_PERMISSION      if the user doesn't have permission to talk to this device
+ *         - \ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device);
+
+/**
+ * Retrieves the name of this device.
+ *
+ * For all products.
+ *
+ * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not
+ * exceed 64 characters in length (including the NULL terminator).  See \ref
+ * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.
+ *
+ * @param device                               The identifier of the target device
+ * @param name                                 Reference in which to return the product name
+ * @param length                               The maximum allowed length of the string returned in \a name
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a name has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a name is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length);
+
+/**
+ * Retrieves the brand of this device.
+ *
+ * For all products.
+ *
+ * The type is a member of \ref nvmlBrandType_t defined above.
+ *
+ * @param device                               The identifier of the target device
+ * @param type                                 Reference in which to return the product brand type
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a name has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a type is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type);
+
+/**
+ * Retrieves the NVML index of this device.
+ *
+ * For all products.
+ *
+ * Valid indices are derived from the \a accessibleDevices count returned by
+ *   \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices
+ *   are 0 and 1, corresponding to GPU 0 and GPU 1.
+ *
+ * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it
+ *   is recommended that devices be looked up by their PCI ids or GPU UUID. See
+ *   \ref nvmlDeviceGetHandleByPciBusId() and \ref nvmlDeviceGetHandleByUUID().
+ *
+ * Note: The NVML index may not correlate with other APIs, such as the CUDA device index.
+ *
+ * @param device                               The identifier of the target device
+ * @param index                                Reference in which to return the NVML index of the device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a index has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a index is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetHandleByIndex()
+ * @see nvmlDeviceGetCount()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index);
+
+/**
+ * Retrieves the globally unique board serial number associated with this device's board.
+ *
+ * For all products with an inforom.
+ *
+ * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator).
+ * This number matches the serial number tag that is physically attached to the board.  See \ref
+ * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE.
+ *
+ * @param device                               The identifier of the target device
+ * @param serial                               Reference in which to return the board/module serial number
+ * @param length                               The maximum allowed length of the string returned in \a serial
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a serial has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a serial is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length);
+
+/**
+ * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device
+ * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2,
+ *     result[0] = 0x3, result[1] = 0x3
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Supported on Linux only.
+ *
+ * @param device                               The identifier of the target device
+ * @param cpuSetSize                           The size of the cpuSet array that is safe to access
+ * @param cpuSet                               Array reference in which to return a bitmask of CPUs, 64 CPUs per
+ *                                                 unsigned long on 64-bit machines, 32 on 32-bit machines
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a cpuAffinity has been filled
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, cpuSetSize == 0, or cpuSet is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet);
+
+/**
+ * Sets the ideal affinity for the calling thread and device using the guidelines
+ * given in nvmlDeviceGetCpuAffinity().  Note, this is a change as of version 8.0.
+ * Older versions set the affinity for a calling process and all children.
+ * Currently supports up to 64 processors.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Supported on Linux only.
+ *
+ * @param device                               The identifier of the target device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the calling process has been successfully bound
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device);
+
+/**
+ * Clear all affinity bindings for the calling thread.  Note, this is a change as of version
+ * 8.0 as older versions cleared the affinity for a calling process and all children.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Supported on Linux only.
+ *
+ * @param device                               The identifier of the target device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the calling process has been successfully unbound
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device);
+
+/**
+ * Retrieve the common ancestor for two devices
+ * For all products.
+ * Supported on Linux only.
+ *
+ * @param device1                              The identifier of the first device
+ * @param device2                              The identifier of the second device
+ * @param pathInfo                             A \ref nvmlGpuTopologyLevel_t that gives the path type
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pathInfo has been set
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device1, or \a device2 is invalid, or \a pathInfo is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo);
+
+/**
+ * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level
+ * For all products.
+ * Supported on Linux only.
+ *
+ * @param device                               The identifier of the first device
+ * @param level                                The \ref nvmlGpuTopologyLevel_t level to search for other GPUs
+ * @param count                                When zero, is set to the number of matching GPUs such that \a deviceArray
+ *                                             can be malloc'd.  When non-zero, \a deviceArray will be filled with \a count
+ *                                             number of device handles.
+ * @param deviceArray                          An array of device handles for GPUs found at \a level
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a deviceArray or \a count (if initially zero) has been set
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a level, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray);
+
+/**
+ * Retrieve the set of GPUs that have a CPU affinity with the given CPU number
+ * For all products.
+ * Supported on Linux only.
+ *
+ * @param cpuNumber                            The CPU number
+ * @param count                                When zero, is set to the number of matching GPUs such that \a deviceArray
+ *                                             can be malloc'd.  When non-zero, \a deviceArray will be filled with \a count
+ *                                             number of device handles.
+ * @param deviceArray                          An array of device handles for GPUs found with affinity to \a cpuNumber
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a deviceArray or \a count (if initially zero) has been set
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a cpuNumber, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery
+ */
+nvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray);
+
+/**
+ * Retrieve the status for a given p2p capability index between a given pair of GPU
+ *
+ * @param device1                              The first device
+ * @param device2                              The second device
+ * @param p2pIndex                             p2p Capability Index being looked for between \a device1 and \a device2
+ * @param p2pStatus                            Reference in which to return the status of the \a p2pIndex
+ *                                             between \a device1 and \a device2
+ * @return
+ *         - \ref NVML_SUCCESS         if \a p2pStatus has been populated
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT     if \a device1 or \a device2 or \a p2pIndex is invalid or \a p2pStatus is NULL
+ *         - \ref NVML_ERROR_UNKNOWN              on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus);
+
+/**
+ * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string,
+ * that augments the immutable, board serial identifier.
+ *
+ * For all products.
+ *
+ * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products.
+ * It does NOT correspond to any identifier printed on the board.  It will not exceed 80 characters in length
+ * (including the NULL terminator).  See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.
+ *
+ * @param device                               The identifier of the target device
+ * @param uuid                                 Reference in which to return the GPU UUID
+ * @param length                               The maximum allowed length of the string returned in \a uuid
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a uuid has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a uuid is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length);
+
+/**
+ * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for
+ * each GPU will have the form /dev/nvidia[minor number].
+ *
+ * For all products.
+ * Supported only for Linux
+ *
+ * @param device                                The identifier of the target device
+ * @param minorNumber                           Reference in which to return the minor number for the device
+ * @return
+ *         - \ref NVML_SUCCESS                 if the minor number is successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a minorNumber is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber);
+
+/**
+ * Retrieves the the device board part number which is programmed into the board's InfoROM
+ *
+ * For all products.
+ *
+ * @param device                                Identifier of the target device
+ * @param partNumber                            Reference to the buffer to return
+ * @param length                                Length of the buffer reference
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a partNumber has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_NOT_SUPPORTED      if the needed VBIOS fields have not been filled
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a device is invalid or \a serial is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length);
+
+/**
+ * Retrieves the version information for the device's infoROM object.
+ *
+ * For all products with an inforom.
+ *
+ * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate
+ * ECC counts. The version of the data structures in this memory may change from time to time. It will not
+ * exceed 16 characters in length (including the NULL terminator).
+ * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE.
+ *
+ * See \ref nvmlInforomObject_t for details on the available infoROM objects.
+ *
+ * @param device                               The identifier of the target device
+ * @param object                               The target infoROM object
+ * @param version                              Reference in which to return the infoROM version
+ * @param length                               The maximum allowed length of the string returned in \a version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a version is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not have an infoROM
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetInforomImageVersion
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length);
+
+/**
+ * Retrieves the global infoROM image version
+ *
+ * For all products with an inforom.
+ *
+ * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board
+ * in contrast to infoROM object version which is only an indicator of supported features.
+ * Version string will not exceed 16 characters in length (including the NULL terminator).
+ * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE.
+ *
+ * @param device                               The identifier of the target device
+ * @param version                              Reference in which to return the infoROM image version
+ * @param length                               The maximum allowed length of the string returned in \a version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a version is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not have an infoROM
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetInforomVersion
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length);
+
+/**
+ * Retrieves the checksum of the configuration stored in the device's infoROM.
+ *
+ * For all products with an inforom.
+ *
+ * Can be used to make sure that two GPUs have the exact same configuration.
+ * Current checksum takes into account configuration stored in PWR and ECC infoROM objects.
+ * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC)
+ *
+ * @param device                               The identifier of the target device
+ * @param checksum                             Reference in which to return the infoROM configuration checksum
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a checksum has been set
+ *         - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a checksum is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum);
+
+/**
+ * Reads the infoROM from the flash and verifies the checksums.
+ *
+ * For all products with an inforom.
+ *
+ * @param device                               The identifier of the target device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if infoROM is not corrupted
+ *         - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device);
+
+/**
+ * Retrieves the display mode for the device.
+ *
+ * For all products.
+ *
+ * This method indicates whether a physical display (e.g. monitor) is currently connected to
+ * any of the device's connectors.
+ *
+ * See \ref nvmlEnableState_t for details on allowed modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param display                              Reference in which to return the display mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a display has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a display is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display);
+
+/**
+ * Retrieves the display active state for the device.
+ *
+ * For all products.
+ *
+ * This method indicates whether a display is initialized on the device.
+ * For example whether X Server is attached to this device and has allocated memory for the screen.
+ *
+ * Display can be active even when no monitor is physically attached.
+ *
+ * See \ref nvmlEnableState_t for details on allowed modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param isActive                             Reference in which to return the display active state
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a isActive has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a isActive is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive);
+
+/**
+ * Retrieves the persistence mode associated with this device.
+ *
+ * For all products.
+ * For Linux only.
+ *
+ * When driver persistence mode is enabled the driver software state is not torn down when the last
+ * client disconnects. By default this feature is disabled.
+ *
+ * See \ref nvmlEnableState_t for details on allowed modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 Reference in which to return the current driver persistence mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a mode has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetPersistenceMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode);
+
+/**
+ * Retrieves the PCI attributes of this device.
+ *
+ * For all products.
+ *
+ * See \ref nvmlPciInfo_t for details on the available PCI info.
+ *
+ * @param device                               The identifier of the target device
+ * @param pci                                  Reference in which to return the PCI info
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pci has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a pci is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci);
+
+/**
+ * Retrieves the maximum PCIe link generation possible with this device and system
+ *
+ * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will
+ * report is generation 1.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param maxLinkGen                           Reference in which to return the max PCIe link generation
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a maxLinkGen has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a maxLinkGen is null
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen);
+
+/**
+ * Retrieves the maximum PCIe link width possible with this device and system
+ *
+ * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report
+ * a max link width of 8.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param maxLinkWidth                         Reference in which to return the max PCIe link generation
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a maxLinkWidth has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a maxLinkWidth is null
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth);
+
+/**
+ * Retrieves the current PCIe link generation
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param currLinkGen                          Reference in which to return the current PCIe link generation
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a currLinkGen has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a currLinkGen is null
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen);
+
+/**
+ * Retrieves the current PCIe link width
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param currLinkWidth                        Reference in which to return the current PCIe link generation
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a currLinkWidth has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a currLinkWidth is null
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth);
+
+/**
+ * Retrieve PCIe utilization information.
+ * This function is querying a byte counter over a 20ms interval and thus is the
+ *   PCIe throughput over that interval.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * This method is not supported in virtual machines running virtual GPU (vGPU).
+ *
+ * @param device                               The identifier of the target device
+ * @param counter                              The specific counter that should be queried \ref nvmlPcieUtilCounter_t
+ * @param value                                Reference in which to return throughput in KB/s
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a value has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a counter is invalid, or \a value is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value);
+
+/**
+ * Retrieve the PCIe replay counter.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param value                                Reference in which to return the counter's value
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a value and \a rollover have been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a value or \a rollover are NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value);
+
+/**
+ * Retrieves the current clock speeds for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlClockType_t for details on available clock information.
+ *
+ * @param device                               The identifier of the target device
+ * @param type                                 Identify which clock domain to query
+ * @param clock                                Reference in which to return the clock speed in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clock has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clock is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device cannot report the specified clock
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock);
+
+/**
+ * Retrieves the maximum clock speeds for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlClockType_t for details on available clock information.
+ *
+ * \note On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks
+ *       by few MHz.
+ *
+ * @param device                               The identifier of the target device
+ * @param type                                 Identify which clock domain to query
+ * @param clock                                Reference in which to return the clock speed in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clock has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clock is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device cannot report the specified clock
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock);
+
+/**
+ * Retrieves the current setting of a clock that applications will use unless an overspec situation occurs.
+ * Can be changed using \ref nvmlDeviceSetApplicationsClocks.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param clockType                            Identify which clock domain to query
+ * @param clockMHz                             Reference in which to return the clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clockMHz has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);
+
+/**
+ * Retrieves the default applications clock that GPU boots with or
+ * defaults to after \ref nvmlDeviceResetApplicationsClocks call.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param clockType                            Identify which clock domain to query
+ * @param clockMHz                             Reference in which to return the default clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clockMHz has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * \see nvmlDeviceGetApplicationsClock
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);
+
+/**
+ * Resets the application clock to the default value
+ *
+ * This is the applications clock that will be used after system reboot or driver reload.
+ * Default value is constant, but the current value an be changed using \ref nvmlDeviceSetApplicationsClocks.
+ *
+ * On Pascal and newer hardware, if clocks were previously locked with \ref nvmlDeviceSetApplicationsClocks,
+ * this call will unlock clocks. This returns clocks their default behavior ofautomatically boosting above
+ * base clocks as thermal limits allow.
+ *
+ * @see nvmlDeviceGetApplicationsClock
+ * @see nvmlDeviceSetApplicationsClocks
+ *
+ * For Fermi &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.
+ *
+ * @param device                               The identifier of the target device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if new settings were successfully set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device);
+
+/**
+ * Retrieves the clock speed for the clock specified by the clock type and clock ID.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param clockType                            Identify which clock domain to query
+ * @param clockId                              Identify which clock in the domain to query
+ * @param clockMHz                             Reference in which to return the clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clockMHz has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz);
+
+/**
+ * Retrieves the customer defined maximum boost clock speed specified by the given clock type.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param clockType                            Identify which clock domain to query
+ * @param clockMHz                             Reference in which to return the clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clockMHz has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device or the \a clockType on this device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);
+
+/**
+ * Retrieves the list of possible memory clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param count                                Reference in which to provide the \a clocksMHz array size, and
+ *                                             to return the number of elements
+ * @param clocksMHz                            Reference in which to return the clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a count and \a clocksMHz have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a count is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to the number of
+ *                                                required elements)
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetApplicationsClocks
+ * @see nvmlDeviceGetSupportedGraphicsClocks
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz);
+
+/**
+ * Retrieves the list of possible graphics clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param memoryClockMHz                       Memory clock for which to return possible graphics clocks
+ * @param count                                Reference in which to provide the \a clocksMHz array size, and
+ *                                             to return the number of elements
+ * @param clocksMHz                            Reference in which to return the clocks in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a count and \a clocksMHz have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_NOT_FOUND         if the specified \a memoryClockMHz is not a supported frequency
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clock is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetApplicationsClocks
+ * @see nvmlDeviceGetSupportedMemoryClocks
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz);
+
+/**
+ * Retrieve the current state of Auto Boosted clocks on a device and store it in \a isEnabled
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates
+ * to maximize performance as thermal limits allow.
+ *
+ * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks.
+ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost
+ * behavior.
+ *
+ * @param device                               The identifier of the target device
+ * @param isEnabled                            Where to store the current state of Auto Boosted clocks of the target device
+ * @param defaultIsEnabled                     Where to store the default Auto Boosted clocks behavior of the target device that the device will
+ *                                                 revert to when no applications are using the GPU
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 If \a isEnabled has been been set with the Auto Boosted clocks state of \a device
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a isEnabled is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled);
+
+/**
+ * Try to set the current state of Auto Boosted clocks on a device.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates
+ * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock
+ * rates are desired.
+ *
+ * Non-root users may use this API by default but can be restricted by root from using this API by calling
+ * \ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS.
+ * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled.
+ *
+ * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks.
+ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost
+ * behavior.
+ *
+ * @param device                               The identifier of the target device
+ * @param enabled                              What state to try to set Auto Boosted clocks of the target device to
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 If the Auto Boosted clocks were successfully set to the state specified by \a enabled
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled);
+
+/**
+ * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will
+ * return to when no compute running processes (e.g. CUDA application which have an active context) are running
+ *
+ * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.
+ * Requires root/admin permissions.
+ *
+ * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates
+ * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock
+ * rates are desired.
+ *
+ * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks.
+ * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost
+ * behavior.
+ *
+ * @param device                               The identifier of the target device
+ * @param enabled                              What state to try to set default Auto Boosted clocks of the target device to
+ * @param flags                                Flags that change the default behavior. Currently Unused.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 If the Auto Boosted clock's default state was successfully set to the state specified by \a enabled
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_NO_PERMISSION     If the calling user does not have permission to change Auto Boosted clock's default state.
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags);
+
+
+/**
+ * Retrieves the intended operating speed of the device's fan.
+ *
+ * Note: The reported speed is the intended fan speed.  If the fan is physically blocked and unable to spin, the
+ * output will not match the actual fan speed.
+ *
+ * For all discrete products with dedicated fans.
+ *
+ * The fan speed is expressed as a percent of the maximum, i.e. full speed is 100%.
+ *
+ * @param device                               The identifier of the target device
+ * @param speed                                Reference in which to return the fan speed percentage
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a speed has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a speed is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not have a fan
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed);
+
+/**
+ * Retrieves the current temperature readings for the device, in degrees C.
+ *
+ * For all products.
+ *
+ * See \ref nvmlTemperatureSensors_t for details on available temperature sensors.
+ *
+ * @param device                               The identifier of the target device
+ * @param sensorType                           Flag that indicates which sensor reading to retrieve
+ * @param temp                                 Reference in which to return the temperature reading
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a temp has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a sensorType is invalid or \a temp is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not have the specified sensor
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp);
+
+/**
+ * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds.
+ *
+ * @param device                               The identifier of the target device
+ * @param thresholdType                        The type of threshold value queried
+ * @param temp                                 Reference in which to return the temperature reading
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a temp has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a thresholdType is invalid or \a temp is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not have a temperature sensor or is unsupported
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp);
+
+/**
+ * Retrieves the current performance state for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlPstates_t for details on allowed performance states.
+ *
+ * @param device                               The identifier of the target device
+ * @param pState                               Reference in which to return the performance state reading
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pState has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a pState is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState);
+
+/**
+ * Retrieves current clocks throttling reasons.
+ *
+ * For all fully supported products.
+ *
+ * \note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once.
+ *
+ * @param device                                The identifier of the target device
+ * @param clocksThrottleReasons                 Reference in which to return bitmask of active clocks throttle
+ *                                                  reasons
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a clocksThrottleReasons has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a clocksThrottleReasons is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlClocksThrottleReasons
+ * @see nvmlDeviceGetSupportedClocksThrottleReasons
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons);
+
+/**
+ * Retrieves bitmask of supported clocks throttle reasons that can be returned by
+ * \ref nvmlDeviceGetCurrentClocksThrottleReasons
+ *
+ * For all fully supported products.
+ *
+ * This method is not supported in virtual machines running virtual GPU (vGPU).
+ *
+ * @param device                               The identifier of the target device
+ * @param supportedClocksThrottleReasons       Reference in which to return bitmask of supported
+ *                                              clocks throttle reasons
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a supportedClocksThrottleReasons has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a supportedClocksThrottleReasons is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlClocksThrottleReasons
+ * @see nvmlDeviceGetCurrentClocksThrottleReasons
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons);
+
+/**
+ * Deprecated: Use \ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization.
+ *
+ * Retrieve the current performance state for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlPstates_t for details on allowed performance states.
+ *
+ * @param device                               The identifier of the target device
+ * @param pState                               Reference in which to return the performance state reading
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pState has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a pState is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState);
+
+/**
+ * This API has been deprecated.
+ *
+ * Retrieves the power management mode associated with this device.
+ *
+ * For products from the Fermi family.
+ *     - Requires \a NVML_INFOROM_POWER version 3.0 or higher.
+ *
+ * For from the Kepler or newer families.
+ *     - Does not require \a NVML_INFOROM_POWER object.
+ *
+ * This flag indicates whether any power management algorithm is currently active on the device. An
+ * enabled state does not necessarily mean the device is being actively throttled -- only that
+ * that the driver will do so if the appropriate conditions are met.
+ *
+ * See \ref nvmlEnableState_t for details on allowed modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 Reference in which to return the current power management mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a mode has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode);
+
+/**
+ * Retrieves the power management limit associated with this device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * The power limit defines the upper boundary for the card's power draw. If
+ * the card's total power draw reaches this limit the power management algorithm kicks in.
+ *
+ * This reading is only available if power management mode is supported.
+ * See \ref nvmlDeviceGetPowerManagementMode.
+ *
+ * @param device                               The identifier of the target device
+ * @param limit                                Reference in which to return the power management limit in milliwatts
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a limit has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a limit is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit);
+
+/**
+ * Retrieves information about possible values of power management limits on this device.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param minLimit                             Reference in which to return the minimum power management limit in milliwatts
+ * @param maxLimit                             Reference in which to return the maximum power management limit in milliwatts
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a minLimit and \a maxLimit have been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a minLimit or \a maxLimit is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetPowerManagementLimit
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit);
+
+/**
+ * Retrieves default power management limit on this device, in milliwatts.
+ * Default power management limit is a power management limit that the device boots with.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param defaultLimit                         Reference in which to return the default power management limit in milliwatts
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a defaultLimit has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a defaultLimit is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit);
+
+/**
+ * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory)
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw.
+ *
+ * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode.
+ *
+ * @param device                               The identifier of the target device
+ * @param power                                Reference in which to return the power usage information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a power has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a power is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support power readings
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power);
+
+/**
+ * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded
+ *
+ * For newer than Pascal &tm; fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param energy                               Reference in which to return the energy consumption information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a energy has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a energy is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support energy readings
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy);
+
+/**
+ * Get the effective power limit that the driver enforces after taking into account all limiters
+ *
+ * Note: This can be different from the \ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere
+ * This includes the out of band power limit interface
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                           The device to communicate with
+ * @param limit                            Reference in which to return the power management limit in milliwatts
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a limit has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a limit is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit);
+
+/**
+ * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot).
+ *
+ * For GK110 M-class and X-class Tesla &tm; products from the Kepler family.
+ * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products.
+ * Not supported on Quadro &reg; and Tesla &tm; C-class products.
+ *
+ * @param device                               The identifier of the target device
+ * @param current                              Reference in which to return the current GOM
+ * @param pending                              Reference in which to return the pending GOM
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a mode has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a current or \a pending is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlGpuOperationMode_t
+ * @see nvmlDeviceSetGpuOperationMode
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending);
+
+/**
+ * Retrieves the amount of used, free and total memory available on the device, in bytes.
+ *
+ * For all products.
+ *
+ * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits.
+ * Under WDDM most device memory is allocated and managed on startup by Windows.
+ *
+ * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated
+ * by all active channels on the device.
+ *
+ * See \ref nvmlMemory_t for details on available memory info.
+ *
+ * @param device                               The identifier of the target device
+ * @param memory                               Reference in which to return the memory information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a memory has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a memory is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory);
+
+/**
+ * Retrieves the current compute mode for the device.
+ *
+ * For all products.
+ *
+ * See \ref nvmlComputeMode_t for details on allowed compute modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 Reference in which to return the current compute mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a mode has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetComputeMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode);
+
+/**
+ * Retrieves the CUDA compute capability of the device.
+ *
+ * For all products.
+ *
+ * Returns the major and minor compute capability version numbers of the
+ * device.  The major and minor versions are equivalent to the
+ * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and
+ * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be
+ * returned by CUDA's cuDeviceGetAttribute().
+ *
+ * @param device                               The identifier of the target device
+ * @param major                                Reference in which to return the major CUDA compute capability
+ * @param minor                                Reference in which to return the minor CUDA compute capability
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a major and \a minor have been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a major or \a minor are NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor);
+
+/**
+ * Retrieves the current and pending ECC modes for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * Only applicable to devices with ECC.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher.
+ *
+ * Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target mode following
+ * the next reboot.
+ *
+ * See \ref nvmlEnableState_t for details on allowed modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param current                              Reference in which to return the current ECC mode
+ * @param pending                              Reference in which to return the pending ECC mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a current and \a pending have been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or either \a current or \a pending is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetEccMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending);
+
+/**
+ * Retrieves the device boardId from 0-N.
+ * Devices with the same boardId indicate GPUs connected to the same PLX.  Use in conjunction with
+ *  \ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well.
+ *  The boardId returned is a unique ID for the current configuration.  Uniqueness and ordering across
+ *  reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and
+ *  the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will
+ *  always return those values but they will always be different from each other).
+ *
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param boardId                              Reference in which to return the device's board ID
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a boardId has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a boardId is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId);
+
+/**
+ * Retrieves whether the device is on a Multi-GPU Board
+ * Devices that are on multi-GPU boards will set \a multiGpuBool to a non-zero value.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param multiGpuBool                         Reference in which to return a zero or non-zero value
+ *                                                 to indicate whether the device is on a multi GPU board
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a multiGpuBool has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a multiGpuBool is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool);
+
+/**
+ * Retrieves the total ECC error counts for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * Only applicable to devices with ECC.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher.
+ * Requires ECC Mode to be enabled.
+ *
+ * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of
+ * errors across the entire device.
+ *
+ * See \ref nvmlMemoryErrorType_t for a description of available error types.\n
+ * See \ref nvmlEccCounterType_t for a description of available counter types.
+ *
+ * @param device                               The identifier of the target device
+ * @param errorType                            Flag that specifies the type of the errors.
+ * @param counterType                          Flag that specifies the counter-type of the errors.
+ * @param eccCounts                            Reference in which to return the specified ECC errors
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a eccCounts has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceClearEccErrorCounts()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts);
+
+/**
+ * Retrieves the detailed ECC error counts for the device.
+ *
+ * @deprecated   This API supports only a fixed set of ECC error locations
+ *               On different GPU architectures different locations are supported
+ *               See \ref nvmlDeviceGetMemoryErrorCounter
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * Only applicable to devices with ECC.
+ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts.
+ * Requires ECC Mode to be enabled.
+ *
+ * Detailed errors provide separate ECC counts for specific parts of the memory system.
+ *
+ * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported.
+ *
+ * See \ref nvmlMemoryErrorType_t for a description of available bit types.\n
+ * See \ref nvmlEccCounterType_t for a description of available counter types.\n
+ * See \ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts.
+ *
+ * @param device                               The identifier of the target device
+ * @param errorType                            Flag that specifies the type of the errors.
+ * @param counterType                          Flag that specifies the counter-type of the errors.
+ * @param eccCounts                            Reference in which to return the specified ECC errors
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a eccCounts has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceClearEccErrorCounts()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts);
+
+/**
+ * Retrieves the requested memory error counter for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts.
+ *
+ * Only applicable to devices with ECC.
+ *
+ * Requires ECC Mode to be enabled.
+ *
+ * See \ref nvmlMemoryErrorType_t for a description of available memory error types.\n
+ * See \ref nvmlEccCounterType_t for a description of available counter types.\n
+ * See \ref nvmlMemoryLocation_t for a description of available counter locations.\n
+ *
+ * @param device                               The identifier of the target device
+ * @param errorType                            Flag that specifies the type of error.
+ * @param counterType                          Flag that specifies the counter-type of the errors.
+ * @param locationType                         Specifies the location of the counter.
+ * @param count                                Reference in which to return the ECC counter
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a count has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a bitTyp,e \a counterType or \a locationType is
+ *                                             invalid, or \a count is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support ECC error reporting in the specified memory
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType,
+                                                   nvmlEccCounterType_t counterType,
+                                                   nvmlMemoryLocation_t locationType, unsigned long long *count);
+
+/**
+ * Retrieves the current utilization rates for the device's major subsystems.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlUtilization_t for details on available utilization rates.
+ *
+ * \note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings.
+ *       This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization.
+ *
+ * @param device                               The identifier of the target device
+ * @param utilization                          Reference in which to return the utilization information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a utilization has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a utilization is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization);
+
+/**
+ * Retrieves the current utilization and sampling size in microseconds for the Encoder
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param utilization                          Reference to an unsigned int for encoder utilization info
+ * @param samplingPeriodUs                     Reference to an unsigned int for the sampling period in US
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a utilization has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs);
+
+/**
+ * Retrieves the current capacity of the device's encoder, in macroblocks per second.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param device                            The identifier of the target device
+ * @param encoderQueryType                  Type of encoder to query
+ * @param encoderCapacity                   Reference to an unsigned int for the encoder capacity
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a encoderCapacity is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a encoderCapacity is NULL, or \a device or \a encoderQueryType
+ *                                              are invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED      if device does not support the encoder specified in \a encodeQueryType
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity);
+
+/**
+ * Retrieves the current encoder statistics for a given device.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param device                            The identifier of the target device
+ * @param sessionCount                      Reference to an unsigned int for count of active encoder sessions
+ * @param averageFps                        Reference to an unsigned int for trailing average FPS of all active sessions
+ * @param averageLatency                    Reference to an unsigned int for encode latency in microseconds
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a sessionCount, \a averageFps and \a averageLatency is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a sessionCount, or \a device or \a averageFps,
+ *                                              or \a averageLatency is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount,
+                                                unsigned int *averageFps, unsigned int *averageLatency);
+
+/**
+ * Retrieves information about active encoder sessions on a target device.
+ *
+ * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfos. The
+ * array elememt count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions
+ * written to the buffer.
+ *
+ * If the supplied buffer is not large enough to accomodate the active session array, the function returns
+ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount.
+ * To query the number of active encoder sessions, call this function with *sessionCount = 0.  The code will return
+ * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param device                            The identifier of the target device
+ * @param sessionCount                      Reference to caller supplied array size, and returns the number of sessions.
+ * @param sessionInfos                      Reference in which to return the session information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a sessionInfos is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE  if \a sessionCount is too small, array element count is returned in \a sessionCount
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a sessionCount is NULL.
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos);
+
+/**
+ * Retrieves the current utilization and sampling size in microseconds for the Decoder
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param utilization                          Reference to an unsigned int for decoder utilization info
+ * @param samplingPeriodUs                     Reference to an unsigned int for the sampling period in US
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a utilization has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs);
+
+/**
+ * Retrieves the current and pending driver model for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * For windows only.
+ *
+ * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached
+ * to the device it must run in WDDM mode. TCC mode is preferred if a display is not attached.
+ *
+ * See \ref nvmlDriverModel_t for details on available driver models.
+ *
+ * @param device                               The identifier of the target device
+ * @param current                              Reference in which to return the current driver model
+ * @param pending                              Reference in which to return the pending driver model
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if either \a current and/or \a pending have been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or both \a current and \a pending are NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the platform is not windows
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceSetDriverModel()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending);
+
+/**
+ * Get VBIOS version of the device.
+ *
+ * For all products.
+ *
+ * The VBIOS version may change from time to time. It will not exceed 32 characters in length
+ * (including the NULL terminator).  See \ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE.
+ *
+ * @param device                               The identifier of the target device
+ * @param version                              Reference to which to return the VBIOS version
+ * @param length                               The maximum allowed length of the string returned in \a version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a version is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length);
+
+/**
+ * Get Bridge Chip Information for all the bridge chips on the board.
+ *
+ * For all fully supported products.
+ * Only applicable to multi-GPU products.
+ *
+ * @param device                                The identifier of the target device
+ * @param bridgeHierarchy                       Reference to the returned bridge chip Hierarchy
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if bridge chip exists
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a bridgeInfo is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if bridge chip not supported on the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy);
+
+/**
+ * Get information about processes with a compute context on a device
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * This function returns information only about compute running processes (e.g. CUDA application which have
+ * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function.
+ *
+ * To query the current number of running compute processes, call this function with *infoCount = 0. The
+ * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call
+ * \a infos is allowed to be NULL.
+ *
+ * The usedGpuMemory field returned is all of the memory used by the application.
+ *
+ * Keep in mind that information returned by this call is dynamic and the number of elements might change in
+ * time. Allocate more space for \a infos table in case new compute processes are spawned.
+ *
+ * @param device                               The identifier of the target device
+ * @param infoCount                            Reference in which to provide the \a infos array size, and
+ *                                             to return the number of returned elements
+ * @param infos                                Reference in which to return the process information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a infoCount and \a infos have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small
+ *                                             \a infoCount will contain minimal amount of space necessary for
+ *                                             the call to complete
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, either of \a infoCount or \a infos is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see \ref nvmlSystemGetProcessName
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos);
+
+/**
+ * Get information about processes with a graphics context on a device
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * This function returns information only about graphics based processes
+ * (eg. applications using OpenGL, DirectX)
+ *
+ * To query the current number of running graphics processes, call this function with *infoCount = 0. The
+ * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call
+ * \a infos is allowed to be NULL.
+ *
+ * The usedGpuMemory field returned is all of the memory used by the application.
+ *
+ * Keep in mind that information returned by this call is dynamic and the number of elements might change in
+ * time. Allocate more space for \a infos table in case new graphics processes are spawned.
+ *
+ * @param device                               The identifier of the target device
+ * @param infoCount                            Reference in which to provide the \a infos array size, and
+ *                                             to return the number of returned elements
+ * @param infos                                Reference in which to return the process information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a infoCount and \a infos have been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small
+ *                                             \a infoCount will contain minimal amount of space necessary for
+ *                                             the call to complete
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, either of \a infoCount or \a infos is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see \ref nvmlSystemGetProcessName
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos);
+
+/**
+ * Check if the GPU devices are on the same physical board.
+ *
+ * For all fully supported products.
+ *
+ * @param device1                               The first GPU device
+ * @param device2                               The second GPU device
+ * @param onSameBoard                           Reference in which to return the status.
+ *                                              Non-zero indicates that the GPUs are on the same board.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a onSameBoard has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a dev1 or \a dev2 are invalid or \a onSameBoard is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this check is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the either GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard);
+
+/**
+ * Retrieves the root/admin permissions on the target API. See \a nvmlRestrictedAPI_t for the list of supported APIs.
+ * If an API is restricted only root users can call that API. See \a nvmlDeviceSetAPIRestriction to change current permissions.
+ *
+ * For all fully supported products.
+ *
+ * @param device                               The identifier of the target device
+ * @param apiType                              Target API type for this operation
+ * @param isRestricted                         Reference in which to return the current restriction
+ *                                             NVML_FEATURE_ENABLED indicates that the API is root-only
+ *                                             NVML_FEATURE_DISABLED indicates that the API is accessible to all users
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a isRestricted has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a apiType incorrect or \a isRestricted is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device or the device does not support
+ *                                                 the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is
+ *                                                 not supported by the device)
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlRestrictedAPI_t
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted);
+
+/**
+ * Gets recent samples for the GPU.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by
+ * the driver.
+ *
+ * Power, Utilization and Clock samples are returned as type "unsigned int" for the union nvmlValue_t.
+ *
+ * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL.
+ * The returned samplesCount will provide the number of samples that can be queried. The user needs to
+ * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t).
+ *
+ * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the
+ * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query
+ * to get more recent samples.
+ *
+ * This method fetches the number of entries which can be accommodated in the provided samples array, and the
+ * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this
+ * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost.
+ *
+ * @param device                        The identifier for the target device
+ * @param type                          Type of sampling event
+ * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp.
+ * @param sampleValType                 Output parameter to represent the type of sample value as described in nvmlSampleVal_t
+ * @param sampleCount                   Reference to provide the number of elements which can be queried in samples array
+ * @param samples                       Reference in which samples are returned
+
+ * @return
+ *         - \ref NVML_SUCCESS                 if samples are successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a samplesCount is NULL or
+ *                                             reference to \a sampleCount is 0 for non null \a samples
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_NOT_FOUND         if sample entries are not found
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp,
+        nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples);
+
+/**
+ * Gets Total, Available and Used size of BAR1 memory.
+ *
+ * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party
+ * devices (peer-to-peer on the PCIE bus).
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param bar1Memory                           Reference in which BAR1 memory
+ *                                             information is returned.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if BAR1 memory is successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a bar1Memory is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory);
+
+
+/**
+ * Gets the duration of time during which the device was throttled (lower than requested clocks) due to power
+ * or thermal constraints.
+ *
+ * The method is important to users who are tying to understand if their GPUs throttle at any point during their applications. The
+ * difference in violation times at two different reference times gives the indication of GPU throttling event.
+ *
+ * Violation for thermal capping is not supported at this time.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param perfPolicyType                       Represents Performance policy which can trigger GPU throttling
+ * @param violTime                             Reference to which violation time related information is returned
+ *
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if violation time is successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a perfPolicyType is invalid, or \a violTime is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime);
+
+/**
+ * @}
+ */
+
+/** @addtogroup nvmlAccountingStats
+ *  @{
+ */
+
+/**
+ * Queries the state of per process accounting mode.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * See \ref nvmlDeviceGetAccountingStats for more details.
+ * See \ref nvmlDeviceSetAccountingMode
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 Reference in which to return the current accounting mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the mode has been successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode are NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode);
+
+/**
+ * Queries process's accounting stats.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * Accounting stats capture GPU utilization and other statistics across the lifetime of a process.
+ * Accounting stats can be queried during life time of the process and after its termination.
+ * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and
+ * updated to actual running time after its termination.
+ * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old
+ * processes.
+ *
+ * See \ref nvmlAccountingStats_t for description of each returned metric.
+ * List of processes that can be queried can be retrieved from \ref nvmlDeviceGetAccountingPids.
+ *
+ * @note Accounting Mode needs to be on. See \ref nvmlDeviceGetAccountingMode.
+ * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be
+ *         queried since they don't contribute to GPU utilization.
+ * @note In case of pid collision stats of only the latest process (that terminated last) will be reported
+ *
+ * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU.
+ *
+ * @param device                               The identifier of the target device
+ * @param pid                                  Process Id of the target process to query stats for
+ * @param stats                                Reference in which to return the process's accounting stats
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if stats have been successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a stats are NULL
+ *         - \ref NVML_ERROR_NOT_FOUND         if process stats were not found
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetAccountingBufferSize
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats);
+
+/**
+ * Queries list of processes that can be queried for accounting stats. The list of processes returned
+ * can be in running or terminated state.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * To just query the number of processes ready to be queried, call this function with *count = 0 and
+ * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty.
+ *
+ * For more details see \ref nvmlDeviceGetAccountingStats.
+ *
+ * @note In case of PID collision some processes might not be accessible before the circular buffer is full.
+ *
+ * @param device                               The identifier of the target device
+ * @param count                                Reference in which to provide the \a pids array size, and
+ *                                               to return the number of elements ready to be queried
+ * @param pids                                 Reference in which to return list of process ids
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if pids were successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a count is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to
+ *                                                 expected value)
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetAccountingBufferSize
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids);
+
+/**
+ * Returns the number of processes that the circular buffer with accounting pids can hold.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * This is the maximum number of processes that accounting information will be stored for before information
+ * about oldest processes will get overwritten by information about new processes.
+ *
+ * @param device                               The identifier of the target device
+ * @param bufferSize                           Reference in which to provide the size (in number of elements)
+ *                                               of the circular buffer for accounting stats.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if buffer size was successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a bufferSize is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetAccountingStats
+ * @see nvmlDeviceGetAccountingPids
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize);
+
+/** @} */
+
+/** @addtogroup nvmlDeviceQueries
+ *  @{
+ */
+
+/**
+ * Returns the list of retired pages by source, including pages that are pending retirement
+ * The address information provided from this API is the hardware address of the page that was retired.  Note
+ * that this does not match the virtual address used in CUDA, but will match the address information in XID 63
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                            The identifier of the target device
+ * @param cause                             Filter page addresses by cause of retirement
+ * @param pageCount                         Reference in which to provide the \a addresses buffer size, and
+ *                                          to return the number of retired pages that match \a cause
+ *                                          Set to 0 to query the size without allocating an \a addresses buffer
+ * @param addresses                         Buffer to write the page addresses into
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pageCount was populated and \a addresses was filled
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the
+ *                                             matching page addresses.  \a pageCount is set to the needed size.
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or
+ *                                             \a addresses is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause,
+    unsigned int *pageCount, unsigned long long *addresses);
+
+/**
+ * Check if any pages are pending retirement and need a reboot to fully retire.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                            The identifier of the target device
+ * @param isPending                         Reference in which to return the pending status
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a isPending was populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a isPending is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlUnitCommands Unit Commands
+ *  This chapter describes NVML operations that change the state of the unit. For S-class products.
+ *  Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION
+ *  error code when invoking any of these methods.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Set the LED state for the unit. The LED can be either green (0) or amber (1).
+ *
+ * For S-class products.
+ * Requires root/admin permissions.
+ *
+ * This operation takes effect immediately.
+ *
+ *
+ * <b>Current S-Class products don't provide unique LEDs for each unit. As such, both front
+ * and back LEDs will be toggled in unison regardless of which unit is specified with this command.</b>
+ *
+ * See \ref nvmlLedColor_t for available colors.
+ *
+ * @param unit                                 The identifier of the target unit
+ * @param color                                The target LED color
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the LED color has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a unit or \a color is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlUnitGetLedState()
+ */
+nvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlDeviceCommands Device Commands
+ *  This chapter describes NVML operations that change the state of the device.
+ *  Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION
+ *  error code when invoking any of these methods.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Set the persistence mode for the device.
+ *
+ * For all products.
+ * For Linux only.
+ * Requires root/admin permissions.
+ *
+ * The persistence mode determines whether the GPU driver software is torn down after the last client
+ * exits.
+ *
+ * This operation takes effect immediately. It is not persistent across reboots. After each reboot the
+ * persistence mode is reset to "Disabled".
+ *
+ * See \ref nvmlEnableState_t for available modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 The target persistence mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the persistence mode was set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetPersistenceMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode);
+
+/**
+ * Set the compute mode for the device.
+ *
+ * For all products.
+ * Requires root/admin permissions.
+ *
+ * The compute mode determines whether a GPU can be used for compute operations and whether it can
+ * be shared across contexts.
+ *
+ * This operation takes effect immediately. Under Linux it is not persistent across reboots and
+ * always resets to "Default". Under windows it is persistent.
+ *
+ * Under windows compute mode may only be set to DEFAULT when running in WDDM
+ *
+ * See \ref nvmlComputeMode_t for details on available compute modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 The target compute mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the compute mode was set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetComputeMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode);
+
+/**
+ * Set the ECC mode for the device.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Only applicable to devices with ECC.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher.
+ * Requires root/admin permissions.
+ *
+ * The ECC mode determines whether the GPU enables its ECC support.
+ *
+ * This operation takes effect after the next reboot.
+ *
+ * See \ref nvmlEnableState_t for details on available modes.
+ *
+ * @param device                               The identifier of the target device
+ * @param ecc                                  The target ECC mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the ECC mode was set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a ecc is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetEccMode()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc);
+
+/**
+ * Clear the ECC error and other memory error counts for the device.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Only applicable to devices with ECC.
+ * Requires \a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts.
+ * Requires \a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts.
+ * Requires root/admin permissions.
+ * Requires ECC Mode to be enabled.
+ *
+ * Sets all of the specified ECC counters to 0, including both detailed and total counts.
+ *
+ * This operation takes effect immediately.
+ *
+ * See \ref nvmlMemoryErrorType_t for details on available counter types.
+ *
+ * @param device                               The identifier of the target device
+ * @param counterType                          Flag that indicates which type of errors should be cleared.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the error counts were cleared
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a counterType is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see
+ *      - nvmlDeviceGetDetailedEccErrors()
+ *      - nvmlDeviceGetTotalEccErrors()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType);
+
+/**
+ * Set the driver model for the device.
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * For windows only.
+ * Requires root/admin permissions.
+ *
+ * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached
+ * to the device it must run in WDDM mode.
+ *
+ * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce).
+ * This should only be done if the host is subsequently powered down and the display is detached from the device
+ * before the next reboot.
+ *
+ * This operation takes effect after the next reboot.
+ *
+ * Windows driver model may only be set to WDDM when running in DEFAULT compute mode.
+ *
+ * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or
+ * will not support it after reboot. See \ref nvmlDeviceSetGpuOperationMode.
+ *
+ * See \ref nvmlDriverModel_t for details on available driver models.
+ * See \ref nvmlFlagDefault and \ref nvmlFlagForce
+ *
+ * @param device                               The identifier of the target device
+ * @param driverModel                          The target driver model
+ * @param flags                                Flags that change the default behavior
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the driver model has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a driverModel is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the platform is not windows or the device does not support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetDriverModel()
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags);
+
+/**
+ * Set clocks that applications will lock to.
+ *
+ * Sets the clocks that compute and graphics applications will be running at.
+ * e.g. CUDA driver requests these clocks during context creation which means this property
+ * defines clocks at which CUDA applications will be running unless some overspec event
+ * occurs (e.g. over power, over thermal or external HW brake).
+ *
+ * Can be used as a setting to request constant performance.
+ *
+ * On Pascal and newer hardware, this will automatically disable automatic boosting of clocks.
+ *
+ * On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance should also call
+ * \ref nvmlDeviceSetAutoBoostedClocksEnabled to prevent clocks from automatically boosting
+ * above the clock value being set.
+ *
+ * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.
+ * Requires root/admin permissions.
+ *
+ * See \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks
+ * for details on how to list available clocks combinations.
+ *
+ * After system reboot or driver reload applications clocks go back to their default value.
+ * See \ref nvmlDeviceResetApplicationsClocks.
+ *
+ * @param device                               The identifier of the target device
+ * @param memClockMHz                          Requested memory clock in MHz
+ * @param graphicsClockMHz                     Requested graphics clock in MHz
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if new settings were successfully set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a memClockMHz and \a graphicsClockMHz
+ *                                                 is not a valid clock combination
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz);
+
+/**
+ * Set new power limit of this device.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Requires root/admin permissions.
+ *
+ * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values.
+ *
+ * \note Limit is not persistent across reboots or driver unloads.
+ * Enable persistent mode to prevent driver from unloading when no application is using the device.
+ *
+ * @param device                               The identifier of the target device
+ * @param limit                                Power management limit in milliwatts to set
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a limit has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a defaultLimit is out of range
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceGetPowerManagementLimitConstraints
+ * @see nvmlDeviceGetPowerManagementDefaultLimit
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit);
+
+/**
+ * Sets new GOM. See \a nvmlGpuOperationMode_t for details.
+ *
+ * For GK110 M-class and X-class Tesla &tm; products from the Kepler family.
+ * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products.
+ * Not supported on Quadro &reg; and Tesla &tm; C-class products.
+ * Requires root/admin permissions.
+ *
+ * Changing GOMs requires a reboot.
+ * The reboot requirement might be removed in the future.
+ *
+ * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when
+ * pending driver model is WDDM is not supported. See \ref nvmlDeviceSetDriverModel.
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 Target GOM
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a mode has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a mode incorrect
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support GOM or specific mode
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlGpuOperationMode_t
+ * @see nvmlDeviceGetGpuOperationMode
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode);
+
+/**
+ * Changes the root/admin restructions on certain APIs. See \a nvmlRestrictedAPI_t for the list of supported APIs.
+ * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs.
+ * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \a nvmlDeviceGetAPIRestriction
+ * to query the current restriction settings.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Requires root/admin permissions.
+ *
+ * @param device                               The identifier of the target device
+ * @param apiType                              Target API type for this operation
+ * @param isRestricted                         The target restriction
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a isRestricted has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a apiType incorrect
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support changing API restrictions or the device does not support
+ *                                                 the feature that api restrictions are being set for (E.G. Enabling/disabling auto
+ *                                                 boosted clocks is not supported by the device)
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlRestrictedAPI_t
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted);
+
+/**
+ * @}
+ */
+
+/** @addtogroup nvmlAccountingStats
+ *  @{
+ */
+
+/**
+ * Enables or disables per process accounting.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Requires root/admin permissions.
+ *
+ * @note This setting is not persistent and will default to disabled after driver unloads.
+ *       Enable persistence mode to be sure the setting doesn't switch off to disabled.
+ *
+ * @note Enabling accounting mode has no negative impact on the GPU performance.
+ *
+ * @note Disabling accounting clears all accounting pids information.
+ *
+ * See \ref nvmlDeviceGetAccountingMode
+ * See \ref nvmlDeviceGetAccountingStats
+ * See \ref nvmlDeviceClearAccountingPids
+ *
+ * @param device                               The identifier of the target device
+ * @param mode                                 The target accounting mode
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the new mode has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a mode are invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode);
+
+/**
+ * Clears accounting information about all processes that have already terminated.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ * Requires root/admin permissions.
+ *
+ * See \ref nvmlDeviceGetAccountingMode
+ * See \ref nvmlDeviceGetAccountingStats
+ * See \ref nvmlDeviceSetAccountingMode
+ *
+ * @param device                               The identifier of the target device
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if accounting information has been cleared
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device are invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup NvLink NvLink Methods
+ * This chapter describes methods that NVML can perform on NVLINK enabled devices.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Retrieves the state of the device's NvLink for the link specified
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param isActive                             \a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that
+ *                                             the link is active and NVML_FEATURE_DISABLED indicates it
+ *                                             is inactive
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a isActive has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a link is invalid or \a isActive is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive);
+
+/**
+ * Retrieves the version of the device's NvLink for the link specified
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param version                              Requested NvLink version
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a link is invalid or \a version is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version);
+
+/**
+ * Retrieves the requested capability from the device's NvLink for the link specified
+ * Please refer to the \a nvmlNvLinkCapability_t structure for the specific caps that can be queried
+ * The return value should be treated as a boolean.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param capability                           Specifies the \a nvmlNvLinkCapability_t to be queried
+ * @param capResult                            A boolean for the queried capability indicating that feature is available
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a capResult has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a link, or \a capability is invalid or \a capResult is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link,
+                                                   nvmlNvLinkCapability_t capability, unsigned int *capResult);
+
+/**
+ * Retrieves the PCI information for the remote node on a NvLink link
+ * Note: pciSubSystemId is not filled in this function and is indeterminate
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param pci                                  \a nvmlPciInfo_t of the remote node for the specified link
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a pci has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a link is invalid or \a pci is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci);
+
+/**
+ * Retrieves the specified error counter value
+ * Please refer to \a nvmlNvLinkErrorCounter_t for error counters that are available
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param counter                              Specifies the NvLink counter to be queried
+ * @param counterValue                         Returned counter value
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a counter has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a link, or \a counter is invalid or \a counterValue is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link,
+                                                     nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue);
+
+/**
+ * Resets all error counters to zero
+ * Please refer to \a nvmlNvLinkErrorCounter_t for the list of error counters that are reset
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the reset is successful
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device or \a link is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link);
+
+/**
+ * Set the NVLINK utilization counter control information for the specified counter, 0 or 1.
+ * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition.  Performs a reset
+ * of the counters if the reset parameter is non-zero.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param counter                              Specifies the counter that should be set (0 or 1).
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param control                              A reference to the \a nvmlNvLinkUtilizationControl_t to set
+ * @param reset                                Resets the counters on set if non-zero
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the control has been set successfully
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a counter, \a link, or \a control is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter,
+                                                           nvmlNvLinkUtilizationControl_t *control, unsigned int reset);
+
+/**
+ * Get the NVLINK utilization counter control information for the specified counter, 0 or 1.
+ * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param counter                              Specifies the counter that should be set (0 or 1).
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param control                              A reference to the \a nvmlNvLinkUtilizationControl_t to place information
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the control has been set successfully
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a counter, \a link, or \a control is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter,
+                                                           nvmlNvLinkUtilizationControl_t *control);
+
+
+/**
+ * Retrieve the NVLINK utilization counter based on the current control for a specified counter.
+ * In general it is good practice to use \a nvmlDeviceSetNvLinkUtilizationControl
+ *  before reading the utilization counters as they have no default state
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param counter                              Specifies the counter that should be read (0 or 1).
+ * @param rxcounter                            Receive counter return value
+ * @param txcounter                            Transmit counter return value
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a rxcounter and \a txcounter have been successfully set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a counter, or \a link is invalid or \a rxcounter or \a txcounter are NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter,
+                                                           unsigned long long *rxcounter, unsigned long long *txcounter);
+
+/**
+ * Freeze the NVLINK utilization counters
+ * Both the receive and transmit counters are operated on by this function
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be queried
+ * @param counter                              Specifies the counter that should be frozen (0 or 1).
+ * @param freeze                               NVML_FEATURE_ENABLED = freeze the receive and transmit counters
+ *                                             NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully frozen or unfrozen
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a link, \a counter, or \a freeze is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link,
+                                            unsigned int counter, nvmlEnableState_t freeze);
+
+/**
+ * Reset the NVLINK utilization counters
+ * Both the receive and transmit counters are operated on by this function
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ *
+ * @param device                               The identifier of the target device
+ * @param link                                 Specifies the NvLink link to be reset
+ * @param counter                              Specifies the counter that should be reset (0 or 1)
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully reset
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device, \a link, or \a counter is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlEvents Event Handling Methods
+ * This chapter describes methods that NVML can perform against each device to register and wait for
+ * some event to occur.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Create an empty set of events.
+ * Event set should be freed by \ref nvmlEventSetFree
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * @param set                                  Reference in which to return the event handle
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the event has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a set is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlEventSetFree
+ */
+nvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set);
+
+/**
+ * Starts recording of events on a specified devices and add the events to specified \ref nvmlEventSet_t
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ * Ecc events are available only on ECC enabled devices (see \ref nvmlDeviceGetTotalEccErrors)
+ * Power capping events are available only on Power Management enabled devices (see \ref nvmlDeviceGetPowerManagementMode)
+ *
+ * For Linux only.
+ *
+ * \b IMPORTANT: Operations on \a set are not thread safe
+ *
+ * This call starts recording of events on specific device.
+ * All events that occurred before this call are not recorded.
+ * Checking if some event occurred can be done with \ref nvmlEventSetWait
+ *
+ * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed.
+ * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes
+ *     are registered in that case.
+ *
+ * @param device                               The identifier of the target device
+ * @param eventTypes                           Bitmask of \ref nvmlEventType to record
+ * @param set                                  Set to which add new event types
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the event has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a eventTypes is invalid or \a set is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the platform does not support this feature or some of requested event types
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlEventType
+ * @see nvmlDeviceGetSupportedEventTypes
+ * @see nvmlEventSetWait
+ * @see nvmlEventSetFree
+ */
+nvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set);
+
+/**
+ * Returns information about events supported on device
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * Events are not supported on Windows. So this function returns an empty mask in \a eventTypes on Windows.
+ *
+ * @param device                               The identifier of the target device
+ * @param eventTypes                           Reference in which to return bitmask of supported events
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the eventTypes has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a eventType is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlEventType
+ * @see nvmlDeviceRegisterEvents
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes);
+
+/**
+ * Waits on events and delivers events
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * If some events are ready to be delivered at the time of the call, function returns immediately.
+ * If there are no events ready to be delivered, function sleeps till event arrives
+ * but not longer than specified timeout. This function in certain conditions can return before
+ * specified timeout passes (e.g. when interrupt arrives)
+ *
+ * In case of xid error, the function returns the most recent xid error type seen by the system. If there are multiple
+ * xid errors generated before nvmlEventSetWait is invoked then the last seen xid error type is returned for all
+ * xid error events.
+ *
+ * @param set                                  Reference to set of events to wait on
+ * @param data                                 Reference in which to return event data
+ * @param timeoutms                            Maximum amount of wait time in milliseconds for registered event
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the data has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a data is NULL
+ *         - \ref NVML_ERROR_TIMEOUT           if no event arrived in specified timeout or interrupt arrived
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if a GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlEventType
+ * @see nvmlDeviceRegisterEvents
+ */
+nvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms);
+
+/**
+ * Releases events in the set
+ *
+ * For Fermi &tm; or newer fully supported devices.
+ *
+ * @param set                                  Reference to events to be released
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if the event has been successfully released
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ *
+ * @see nvmlDeviceRegisterEvents
+ */
+nvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlZPI Drain states
+ * This chapter describes methods that NVML can perform against each device to control their drain state
+ * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to
+ * power on/off GPUs, enable robust reset scenarios, etc.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Modify the drain state of a GPU.  This method forces a GPU to no longer accept new incoming requests.
+ * Any new NVML process will no longer see this GPU.  Persistence mode for this GPU must be turned off before
+ * this call is made.
+ * Must be called as administrator.
+ * For Linux only.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ * Some Kepler devices supported.
+ *
+ * @param pciInfo                              The PCI address of the GPU drain state to be modified
+ * @param newState                             The drain state that should be entered, see \ref nvmlEnableState_t
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully reset
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a nvmlIndex or \a newState is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the calling process has insufficient permissions to perform operation
+ *         - \ref NVML_ERROR_IN_USE            if the device has persistence mode turned on
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState);
+
+/**
+ * Query the drain state of a GPU.  This method is used to check if a GPU is in a currently draining
+ * state.
+ * For Linux only.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ * Some Kepler devices supported.
+ *
+ * @param pciInfo                              The PCI address of the GPU drain state to be queried
+ * @param currentState                         The current drain state for this GPU, see \ref nvmlEnableState_t
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully reset
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a nvmlIndex or \a currentState is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState);
+
+/**
+ * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver
+ * as long as no other processes are attached. If other processes are attached, this call will return
+ * NVML_ERROR_IN_USE and the GPU will be returned to its original "draining" state. Note: the
+ * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called
+ * to initiate the draining state is if that process was using, and is still using, a GPU before the
+ * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled
+ * prior to this call.
+ *
+ * For long-running NVML processes please note that this will change the enumeration of current GPUs.
+ * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2.
+ * Also, device handles after the removed GPU will not be valid and must be re-established.
+ * Must be run as administrator.
+ * For Linux only.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ * Some Kepler devices supported.
+ *
+ * @param pciInfo                              The PCI address of the GPU to be removed
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully reset
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a nvmlIndex is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature
+ *         - \ref NVML_ERROR_IN_USE            if the device is still in use and cannot be removed
+ */
+nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu (nvmlPciInfo_t *pciInfo);
+
+/**
+ * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that
+ * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device.
+ * If all are zeroes then the entire PCI tree will be searched.  Please note that for long-running NVML processes
+ * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order.
+ *
+ * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds
+ * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery.
+ *
+ * Must be run as administrator.
+ * For Linux only.
+ *
+ * For Pascal &tm; or newer fully supported devices.
+ * Some Kepler devices supported.
+ *
+ * @param pciInfo                              The PCI tree to be searched.  Only the domain, bus, and device
+ *                                             fields are used in this call.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if counters were successfully reset
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a pciInfo is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the operating system does not support this feature
+ *         - \ref NVML_ERROR_OPERATING_SYSTEM  if the operating system is denying this feature
+ *         - \ref NVML_ERROR_NO_PERMISSION     if the calling process has insufficient permissions to perform operation
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlFieldValueQueries Field Value Queries
+ *  This chapter describes NVML operations that are associated with retrieving Field Values from NVML
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * Request values for a list of fields for a device. This API allows multiple fields to be queried at once.
+ * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs
+ * will be populated from a single call rather than making a driver call for each fieldId.
+ *
+ * @param device                               The device handle of the GPU to request field values for
+ * @param valuesCount                          Number of entries in values that should be retrieved
+ * @param values                               Array of \a valuesCount structures to hold field values.
+ *                                             Each value's fieldId must be populated prior to this call
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if any values in \a values were populated. Note that you must
+ *                                             check the nvmlReturn field of each value for each individual
+ *                                             status
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid or \a values is NULL
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values);
+
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlGridQueries Grid Queries
+ *  This chapter describes NVML operations that are associated with NVIDIA GRID products.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * This method is used to get the virtualization mode corresponding to the GPU.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                    Identifier of the target device
+ * @param pVirtualMode              Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_?
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a pVirtualMode is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a device is invalid or \a pVirtualMode is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlGridCommands Grid Commands
+ *  This chapter describes NVML operations that are associated with NVIDIA GRID products.
+ *  @{
+ */
+/***************************************************************************************************/
+
+/**
+ * This method is used to set the virtualization mode corresponding to the GPU.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                    Identifier of the target device
+ * @param virtualMode               virtualization mode. One of NVML_GPU_VIRTUALIZATION_?
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a pVirtualMode is set
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a device is invalid or \a pVirtualMode is NULL
+ *         - \ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_NOT_SUPPORTED      if setting of virtualization mode is not supported.
+ *         - \ref NVML_ERROR_NO_PERMISSION      if setting of virtualization mode is not allowed for this client.
+ */
+nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode);
+
+/** @} */
+
+/***************************************************************************************************/
+/** @defgroup nvmlVgpu vGPU Management
+ * @{
+ *
+ * Set of APIs supporting GRID vGPU
+ */
+/***************************************************************************************************/
+
+/**
+ * Retrieve the supported vGPU types on a physical GPU (device).
+ *
+ * An array of supported vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer
+ * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount
+ * is used to return the number of vGPU types written to the buffer.
+ *
+ * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns
+ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount.
+ * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0.
+ * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported.
+ *
+ * @param device                   The identifier of the target device
+ * @param vgpuCount                Pointer to caller-supplied array size, and returns number of vGPU types
+ * @param vgpuTypeIds              Pointer to caller-supplied array in which to return list of vGPU types
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                      successful completion
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE      \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT       if \a vgpuCount is NULL or \a device is invalid
+ *         - \ref NVML_ERROR_NOT_SUPPORTED          if vGPU is not supported by the device
+ *         - \ref NVML_ERROR_VGPU_ECC_NOT_SUPPORTED if ECC is enabled on the device
+ *         - \ref NVML_ERROR_UNKNOWN             on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds);
+
+/**
+ * Retrieve the currently creatable vGPU types on a physical GPU (device).
+ *
+ * An array of creatable vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer
+ * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount
+ * is used to return the number of vGPU types written to the buffer.
+ *
+ * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types
+ * can concurrently run on a device.  For example, if only one vGPU type is allowed at a time on a device, then the creatable
+ * list will be restricted to whatever vGPU type is already running on the device.
+ *
+ * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns
+ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount.
+ * To query the number of vGPU types createable for the GPU, call this function with *vgpuCount = 0.
+ * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable.
+ *
+ * @param device                   The identifier of the target device
+ * @param vgpuCount                Pointer to caller-supplied array size, and returns number of vGPU types
+ * @param vgpuTypeIds              Pointer to caller-supplied array in which to return list of vGPU types
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                      successful completion
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE      \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT       if \a vgpuCount is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED          if vGPU is not supported by the device
+ *         - \ref NVML_ERROR_VGPU_ECC_NOT_SUPPORTED if ECC is enabled on the device
+ *         - \ref NVML_ERROR_UNKNOWN                on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds);
+
+/**
+ * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator).
+ * See \ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param vgpuTypeClass            Pointer to string array to return class in
+ * @param size                     Size of string
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                   successful completion
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT    if \a vgpuTypeId is invalid, or \a vgpuTypeClass is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE   if \a size is too small
+ *         - \ref NVML_ERROR_UNKNOWN             on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size);
+
+/**
+ * Retrieve the vGPU type name.
+ *
+ * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not
+ * exceed 64 characters in length (including the NUL terminator).  See \ref
+ * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param vgpuTypeName             Pointer to buffer to return name
+ * @param size                     Size of buffer
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a name is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size);
+
+/**
+ * Retrieve the device ID of a vGPU type.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param deviceID                 Device ID and vendor ID of the device contained in single 32 bit value
+ * @param subsystemID              Subsytem ID and subsytem vendor ID of the device contained in single 32 bit value
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a deviceId or \a subsystemID are NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID);
+
+/**
+ * Retrieve the vGPU framebuffer size in bytes.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param fbSize                   Pointer to framebuffer size in bytes
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a fbSize is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize);
+
+/**
+ * Retrieve count of vGPU's supported display heads.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param numDisplayHeads          Pointer to number of display heads
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a numDisplayHeads is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads);
+
+/**
+ * Retrieve vGPU display head's maximum supported resolution.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param displayIndex             Zero-based index of display head
+ * @param xdim                     Pointer to maximum number of pixels in X dimension
+ * @param ydim                     Pointer to maximum number of pixels in Y dimension
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a xdim or \a ydim are NULL, or \a displayIndex
+ *                                             is out of range.
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim);
+
+/**
+ * Retrieve license requirements for a vGPU type
+ *
+ * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form
+ * "<license name>,<version>", for example "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license,
+ * the licenses are delimited by a semicolon, for example "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0".
+ *
+ * The total length of the returned string will not exceed 128 characters, including the NUL terminator.
+ * See \ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param vgpuTypeLicenseString    Pointer to buffer to return license info
+ * @param size                     Size of \a vgpuTypeLicenseString buffer
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid, or \a vgpuTypeLicenseString is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size);
+
+/**
+ * Retrieve the static frame rate limit value of the vGPU type
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param frameRateLimit           Reference to return the frame rate limit value
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if frame rate limiter is turned off for the vGPU type
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, or \a frameRateLimit is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit);
+
+/**
+ * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                   The identifier of the target device
+ * @param vgpuTypeId               Handle to vGPU type
+ * @param vgpuInstanceCount        Pointer to get the max number of vGPU instances
+ *                                 that can be created on a deicve for given vgpuTypeId
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuTypeId is invalid or is not supported on target device,
+ *                                             or \a vgpuInstanceCount is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount);
+
+/**
+ * Retrieve the active vGPU instances on a device.
+ *
+ * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \a vgpuInstances. The
+ * array elememt count is passed in \a vgpuCount, and \a vgpuCount is used to return the number of vGPU instances
+ * written to the buffer.
+ *
+ * If the supplied buffer is not large enough to accomodate the vGPU instance array, the function returns
+ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \a vgpuCount.
+ * To query the number of active vGPU instances, call this function with *vgpuCount = 0.  The code will return
+ * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param device                   The identifier of the target device
+ * @param vgpuCount                Pointer which passes in the array size as well as get
+ *                                 back the number of types
+ * @param vgpuInstances            Pointer to array in which to return list of vGPU instances
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a device is invalid, or \a vgpuCount is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE  if \a size is too small
+ *         - \ref NVML_ERROR_NOT_SUPPORTED      if vGPU is not supported by the device
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances);
+
+/**
+ * Retrieve the VM ID associated with a vGPU instance.
+ *
+ * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator).
+ * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.
+ *
+ * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \a vmIdType.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param vmId                     Pointer to caller-supplied buffer to hold VM ID
+ * @param size                     Size of buffer in bytes
+ * @param vmIdType                 Pointer to hold VM ID type
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a vmId or \a vmIdType are NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType);
+
+/**
+ * Retrieve the UUID of a vGPU instance.
+ *
+ * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string,
+ * not exceeding 80 characters in length (including the NULL terminator).
+ * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param uuid                     Pointer to caller-supplied buffer to hold vGPU UUID
+ * @param size                     Size of buffer in bytes
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a uuid is NULL
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size);
+
+/**
+ * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU.
+ *
+ * The version is returned as an alphanumeric string in the caller-supplied buffer \a version. The length of the version
+ * string will not exceed 80 characters in length (including the NUL terminator).
+ * See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE.
+ *
+ * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is
+ * returned as "Unknown" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the
+ * NVIDIA driver is loaded and initialized.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param version                  Caller-supplied buffer to return driver version string
+ * @param length                   Size of \a version buffer
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a version has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length);
+
+/**
+ * Retrieve the framebuffer usage in bytes.
+ *
+ * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             The identifier of the target instance
+ * @param fbUsage                  Pointer to framebuffer usage in bytes
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 successful completion
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a fbUsage is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage);
+
+/**
+ * Retrieve the current licensing state of the vGPU instance.
+ *
+ * If the vGPU is currently licensed, \a licensed is set to 1, otherwise it is set to 0.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param licensed                 Reference to return the licensing status
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a licensed has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a licensed is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed);
+
+/**
+ * Retrieve the vGPU type of a vGPU instance.
+ *
+ * Returns the vGPU type ID of vgpu assigned to the vGPU instance.
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param vgpuTypeId               Reference to return the vgpuTypeId
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a vgpuTypeId has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a vgpuTypeId is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId);
+
+/**
+ * Retrieve the frame rate limit set for the vGPU instance.
+ *
+ * Returns the value of the frame rate limit set for the vGPU instance
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param frameRateLimit           Reference to return the frame rate limit
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a frameRateLimit has been set
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if frame rate limiter is turned off for the vGPU type
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a frameRateLimit is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit);
+
+/**
+ * Retrieve the encoder Capacity of a vGPU instance, in macroblocks per second.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param encoderCapacity          Reference to an unsigned int for the encoder capacity
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a encoderCapacity has been retrived
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid, or \a encoderQueryType is invalid
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity);
+
+/**
+ * Set the encoder Capacity of a vGPU instance, in macroblocks per second.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance             Identifier of the target vGPU instance
+ * @param encoderCapacity          Unsigned int for the encoder capacity value
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a encoderCapacity has been set
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a vgpuInstance is invalid
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int  encoderCapacity);
+
+/**
+ * Retrieves current utilization for vGPUs on a physical GPU (device).
+ *
+ * For Kepler &tm; or newer fully supported devices.
+ *
+ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running
+ * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer
+ * pointed at by \a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the
+ * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values
+ * in nvmlValue_t unions. The function sets the caller-supplied \a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to
+ * indicate the returned value type.
+ *
+ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with
+ * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance
+ * count in \a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate
+ * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with
+ * the allocated buffer passed in \a utilizationSamples, and \a vgpuInstanceSamplesCount set to the number of entries the
+ * buffer is sized for.
+ *
+ * On successful return, the function updates \a vgpuInstanceSampleCount with the number of vGPU utilization sample
+ * structures that were actually written. This may differ from a previously read value as vGPU instances are created or
+ * destroyed.
+ *
+ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
+ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp
+ * to a timeStamp retrieved from a previous query to read utilization since the previous query.
+ *
+ * @param device                        The identifier for the target device
+ * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp.
+ * @param sampleValType                 Pointer to caller-supplied buffer to hold the type of returned sample values
+ * @param vgpuInstanceSamplesCount      Pointer to caller-supplied array size, and returns number of vGPU instances
+ * @param utilizationSamples            Pointer to caller-supplied buffer in which vGPU utilization samples are returned
+
+ * @return
+ *         - \ref NVML_SUCCESS                 if utilization samples are successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a vgpuInstanceSamplesCount or \a sampleValType is
+ *                                             NULL, or a sample count of 0 is passed with a non-NULL \a utilizationSamples
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuInstanceSamplesCount is too small to return samples for all
+ *                                             vGPU instances currently executing on the device
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if vGPU is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_NOT_FOUND         if sample entries are not found
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp,
+                                                  nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount,
+                                                  nvmlVgpuInstanceUtilizationSample_t *utilizationSamples);
+
+/**
+ * Retrieves current utilization for processes running on vGPUs on a physical GPU (device).
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on
+ * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the
+ * caller-supplied buffer pointed at by \a utilizationSamples. One utilization sample structure is returned per process running
+ * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which
+ * the samples were recorded. Individual utilization values are returned as "unsigned int" values.
+ *
+ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with
+ * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance
+ * count in \a vgpuProcessSamplesCount. The caller should allocate a buffer of size
+ * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with
+ * the allocated buffer passed in \a utilizationSamples, and \a vgpuProcessSamplesCount set to the number of entries the
+ * buffer is sized for.
+ *
+ * On successful return, the function updates \a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample
+ * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active
+ * in any given sample period.
+ *
+ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
+ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp
+ * to a timeStamp retrieved from a previous query to read utilization since the previous query.
+ *
+ * @param device                        The identifier for the target device
+ * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp.
+ * @param vgpuProcessSamplesCount       Pointer to caller-supplied array size, and returns number of processes running on vGPU instances
+ * @param utilizationSamples            Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned
+
+ * @return
+ *         - \ref NVML_SUCCESS                 if utilization samples are successfully retrieved
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a vgpuProcessSamplesCount or a sample count of 0 is
+ *                                             passed with a non-NULL \a utilizationSamples
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuProcessSamplesCount is too small to return samples for all
+ *                                             vGPU instances currently executing on the device
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if vGPU is not supported by the device
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_NOT_FOUND         if sample entries are not found
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp,
+                                                         unsigned int *vgpuProcessSamplesCount,
+                                                         nvmlVgpuProcessUtilizationSample_t *utilizationSamples);
+/**
+ * Retrieve the GRID licensable features.
+ *
+ * Identifies whether the system supports GRID Software Licensing. If it does, return the list of licensable feature(s)
+ * and their current license status.
+ *
+ * @param device                    Identifier of the target device
+ * @param pGridLicensableFeatures   Pointer to structure in which GRID licensable features are returned
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                 if licensable features are successfully retrieved
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a pGridLicensableFeatures is NULL
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures);
+
+/**
+ * Retrieves the current encoder statistics of a vGPU Instance
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance                      Identifier of the target vGPU instance
+ * @param sessionCount                      Reference to an unsigned int for count of active encoder sessions
+ * @param averageFps                        Reference to an unsigned int for trailing average FPS of all active sessions
+ * @param averageLatency                    Reference to an unsigned int for encode latency in microseconds
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a sessionCount, \a averageFps and \a averageLatency is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a sessionCount , or \a averageFps or \a averageLatency is NULL
+ *                                              or \a vgpuInstance is invalid.
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount,
+                                                     unsigned int *averageFps, unsigned int *averageLatency);
+
+/**
+ * Retrieves information about all active encoder sessions on a vGPU Instance.
+ *
+ * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The
+ * array elememt count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions
+ * written to the buffer.
+ *
+ * If the supplied buffer is not large enough to accomodate the active session array, the function returns
+ * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount.
+ * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return
+ * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount.
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * @param vgpuInstance                      Identifier of the target vGPU instance
+ * @param sessionCount                      Reference to caller supplied array size, and returns
+ *                                          the number of sessions.
+ * @param sessionInfo                       Reference to caller supplied array in which the list
+ *                                          of session information us returned.
+ *
+ * @return
+ *         - \ref NVML_SUCCESS                  if \a sessionInfo is fetched
+ *         - \ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INSUFFICIENT_SIZE  if \a sessionCount is too small, array element count is
+                                                returned in \a sessionCount
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT   if \a sessionCount is NULL or \a vgpuInstance is invalid..
+ *         - \ref NVML_ERROR_UNKNOWN            on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo);
+
+/**
+ * Retrieves the current utilization and process ID
+ *
+ * For Maxwell &tm; or newer fully supported devices.
+ *
+ * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running.
+ * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at
+ * by \a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization
+ * during the last sample period. It includes the CPU timestamp at which  the samples were recorded. Individual utilization values
+ * are returned as "unsigned int" values.
+ *
+ * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with
+ * \a utilization set to NULL. The caller should allocate a buffer of size
+ * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed
+ * in \a utilization, and \a processSamplesCount set to the number of entries the buffer is sized for.
+ *
+ * On successful return, the function updates \a processSamplesCount with the number of process utilization sample
+ * structures that were actually written. This may differ from a previously read value as instances are created or
+ * destroyed.
+ *
+ * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
+ * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp
+ * to a timeStamp retrieved from a previous query to read utilization since the previous query.
+ *
+ * @param device                    The identifier of the target device
+ * @param utilization               Pointer to caller-supplied buffer in which guest process utilization samples are returned
+ * @param processSamplesCount       Pointer to caller-supplied array size, and returns number of processes running
+ * @param lastSeenTimeStamp         Return only samples with timestamp greater than lastSeenTimeStamp.
+
+ * @return
+ *         - \ref NVML_SUCCESS                 if \a utilization has been populated
+ *         - \ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized
+ *         - \ref NVML_ERROR_INVALID_ARGUMENT  if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL
+ *         - \ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature
+ *         - \ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible
+ *         - \ref NVML_ERROR_UNKNOWN           on any unexpected error
+ */
+nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization,
+                                              unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp);
+
+/** @} */
+
+/**
+ * NVML API versioning support
+ */
+#if defined(__NVML_API_VERSION_INTERNAL)
+#undef nvmlDeviceGetNvLinkRemotePciInfo
+#undef nvmlDeviceGetPciInfo
+#undef nvmlDeviceGetCount
+#undef nvmlDeviceGetHandleByIndex
+#undef nvmlDeviceGetHandleByPciBusId
+#undef nvmlInit
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/polymer/README.chromium b/third_party/polymer/README.chromium
index 47d91396..e038fc8 100644
--- a/third_party/polymer/README.chromium
+++ b/third_party/polymer/README.chromium
@@ -44,6 +44,9 @@
   handler code which was hiding ripples for pointer interactions.
 - Bundled and minified Polymer 2 with minify_polymer.py, since Polymer 2 repo
   does not distribute minified files (unlike Polymer 1).
+- For iron-list, call event.preventDefault() when up/down arrow is pressed and
+  the focused item changes. This is to prevent outer vertical scroll from
+  scrolling when the iron-list vertical scroll has reached the top or bottom.
 
 To restore a content of the 'components-chromium' directory from scratch, run
 ./v1_0/reproduce.sh on a Linux machine.
diff --git a/third_party/polymer/v1_0/chromium.patch b/third_party/polymer/v1_0/chromium.patch
index f7ae112..edc9030 100644
--- a/third_party/polymer/v1_0/chromium.patch
+++ b/third_party/polymer/v1_0/chromium.patch
@@ -180,3 +180,29 @@
      });
  
      /**
+diff --git a/components-chromium/iron-list/iron-list-extracted.js b/components-chromium/iron-list/iron-list-extracted.js
+index 4fdfbdead5ae..dbfbc9ca3907 100644
+--- a/components-chromium/iron-list/iron-list-extracted.js
++++ b/components-chromium/iron-list/iron-list-extracted.js
+@@ -1611,13 +1611,20 @@
+     _keydownHandler: function(e) {
+       switch (e.keyCode) {
+         case /* ARROW_DOWN */ 40:
+-          e.preventDefault();
++          // TODO (aee): remove when iron-list issue is fixed.
++          // https://github.com/PolymerElements/iron-list/issues/542
++          if (this._focusedVirtualIndex < this._virtualCount - 1)
++            e.preventDefault();
+           this._focusPhysicalItem(this._focusedVirtualIndex + (this.grid ? this._itemsPerRow : 1));
+           break;
+         case /* ARROW_RIGHT */ 39:
+           if (this.grid) this._focusPhysicalItem(this._focusedVirtualIndex + (this._isRTL ? -1 : 1));
+           break;
+         case /* ARROW_UP */ 38:
++          // TODO (aee): remove when iron-list issue is fixed.
++          // https://github.com/PolymerElements/iron-list/issues/542
++          if (this._focusedVirtualIndex > 0)
++            e.preventDefault();
+           this._focusPhysicalItem(this._focusedVirtualIndex - (this.grid ? this._itemsPerRow : 1));
+           break;
+         case /* ARROW_LEFT */ 37:
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
index 4fdfbdead5..dbfbc9c 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js
@@ -1611,13 +1611,20 @@
     _keydownHandler: function(e) {
       switch (e.keyCode) {
         case /* ARROW_DOWN */ 40:
-          e.preventDefault();
+          // TODO (aee): remove when iron-list issue is fixed.
+          // https://github.com/PolymerElements/iron-list/issues/542
+          if (this._focusedVirtualIndex < this._virtualCount - 1)
+            e.preventDefault();
           this._focusPhysicalItem(this._focusedVirtualIndex + (this.grid ? this._itemsPerRow : 1));
           break;
         case /* ARROW_RIGHT */ 39:
           if (this.grid) this._focusPhysicalItem(this._focusedVirtualIndex + (this._isRTL ? -1 : 1));
           break;
         case /* ARROW_UP */ 38:
+          // TODO (aee): remove when iron-list issue is fixed.
+          // https://github.com/PolymerElements/iron-list/issues/542
+          if (this._focusedVirtualIndex > 0)
+            e.preventDefault();
           this._focusPhysicalItem(this._focusedVirtualIndex - (this.grid ? this._itemsPerRow : 1));
           break;
         case /* ARROW_LEFT */ 37:
diff --git a/third_party/pywebsocket/BUILD.gn b/third_party/pywebsocket/BUILD.gn
index 3f2bf45..c39e56e2 100644
--- a/third_party/pywebsocket/BUILD.gn
+++ b/third_party/pywebsocket/BUILD.gn
@@ -5,8 +5,8 @@
 # pwebsocket is a Python program. Depend on this to get the data deps necessary
 # to run it in the test environment.
 group("pywebsocket") {
-  # For now, depend on the entire directory.
+  # For now, depend on the mod_pywebsocket directory.
   data = [
-    "//third_party/pywebsocket/",
+    "//third_party/pywebsocket/src/mod_pywebsocket/",
   ]
 }
diff --git a/third_party/pywebsocket/README.chromium b/third_party/pywebsocket/README.chromium
index 8f7963c..88c4b0aa 100644
--- a/third_party/pywebsocket/README.chromium
+++ b/third_party/pywebsocket/README.chromium
@@ -3,7 +3,7 @@
 URL: https://github.com/google/pywebsocket/
 Version: 0
 License: New BSD
-License File: NOT_SHIPPED
+License File: LICENSE
 Security Critical: no
 
 Description:
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
index fd17c6e9..03fb7d5 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.13.0 */
+/* Generated by wayland-scanner 1.14.0 */
 
 #ifndef REMOTE_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
 #define REMOTE_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
@@ -843,8 +843,8 @@
 	 */
 	void (*bounds_changed)(void *data,
 			       struct zcr_remote_surface_v1 *zcr_remote_surface_v1,
-			       uint32_t workspace_id_hi,
-			       uint32_t workspace_id_lo,
+			       uint32_t display_id_hi,
+			       uint32_t display_id_lo,
 			       int32_t x,
 			       int32_t y,
 			       int32_t width,
@@ -934,6 +934,7 @@
 #define ZCR_REMOTE_SURFACE_V1_SET_EXTRA_TITLE 38
 #define ZCR_REMOTE_SURFACE_V1_SET_ORIENTATION_LOCK 39
 #define ZCR_REMOTE_SURFACE_V1_PIP 40
+#define ZCR_REMOTE_SURFACE_V1_SET_BOUNDS 41
 
 /**
  * @ingroup iface_zcr_remote_surface_v1
@@ -1128,6 +1129,10 @@
  * @ingroup iface_zcr_remote_surface_v1
  */
 #define ZCR_REMOTE_SURFACE_V1_PIP_SINCE_VERSION 15
+/**
+ * @ingroup iface_zcr_remote_surface_v1
+ */
+#define ZCR_REMOTE_SURFACE_V1_SET_BOUNDS_SINCE_VERSION 18
 
 /** @ingroup iface_zcr_remote_surface_v1 */
 static inline void
@@ -1179,9 +1184,9 @@
 /**
  * @ingroup iface_zcr_remote_surface_v1
  *
- * The window geometry of a window is its "visible bounds" from the
- * user's perspective. Client-side decorations often have invisible
- * portions like drop-shadows which should be ignored for the
+ * [Deprecated] The window geometry of a window is its "visible bounds"
+ * from the user's perspective. Client-side decorations often have
+ * invisible portions like drop-shadows which should be ignored for the
  * purposes of aligning, placing and constraining windows.
  *
  * The window geometry is double buffered, and will be applied at the
@@ -1537,7 +1542,7 @@
 /**
  * @ingroup iface_zcr_remote_surface_v1
  *
- * Start an interactive, user-driven move of the surface.
+ * [Deprecated] Start an interactive, user-driven move of the surface.
  *
  * The compositor responds to this request with a configure event that
  * transitions to the "moving" state. The client must only initiate motion
@@ -1815,6 +1820,36 @@
 			 ZCR_REMOTE_SURFACE_V1_PIP);
 }
 
+/**
+ * @ingroup iface_zcr_remote_surface_v1
+ *
+ * Set the "visible bounds" of a window from the user's perspective.
+ * Client-side decorations often have invisible portions like drop shadows
+ * which should be ignored for the purposes of aligning, placing and
+ * constraining windows.
+ *
+ * The bounds are double buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * Once the bounds are set, it is not possible to unset them, and they will
+ * remain the same until set_bounds is called again, even if a new sub-
+ * surface or buffer is attached.
+ *
+ * If never set, the value is the surface content bounds. This updates
+ * dynamically on every commit.
+ *
+ * The bounds are relative to the given display. If the display is invalid,
+ * they are assumed to be relative to the primary display.
+ *
+ * The width and height must be greater than zero.
+ */
+static inline void
+zcr_remote_surface_v1_set_bounds(struct zcr_remote_surface_v1 *zcr_remote_surface_v1, uint32_t display_id_hi, uint32_t display_id_lo, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
+			 ZCR_REMOTE_SURFACE_V1_SET_BOUNDS, display_id_hi, display_id_lo, x, y, width, height);
+}
+
 #define ZCR_NOTIFICATION_SURFACE_V1_DESTROY 0
 #define ZCR_NOTIFICATION_SURFACE_V1_SET_APP_ID 1
 
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
index 555b6a34a..5be556df 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.13.0 */
+/* Generated by wayland-scanner 1.14.0 */
 
 #ifndef REMOTE_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
 #define REMOTE_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
@@ -708,10 +708,11 @@
 	/**
 	 * set the new window geometry
 	 *
-	 * The window geometry of a window is its "visible bounds" from
-	 * the user's perspective. Client-side decorations often have
-	 * invisible portions like drop-shadows which should be ignored for
-	 * the purposes of aligning, placing and constraining windows.
+	 * [Deprecated] The window geometry of a window is its "visible
+	 * bounds" from the user's perspective. Client-side decorations
+	 * often have invisible portions like drop-shadows which should be
+	 * ignored for the purposes of aligning, placing and constraining
+	 * windows.
 	 *
 	 * The window geometry is double buffered, and will be applied at
 	 * the time wl_surface.commit of the corresponding wl_surface is
@@ -997,7 +998,8 @@
 	/**
 	 * start an interactive move
 	 *
-	 * Start an interactive, user-driven move of the surface.
+	 * [Deprecated] Start an interactive, user-driven move of the
+	 * surface.
 	 *
 	 * The compositor responds to this request with a configure event
 	 * that transitions to the "moving" state. The client must only
@@ -1231,6 +1233,38 @@
 	 */
 	void (*pip)(struct wl_client *client,
 		    struct wl_resource *resource);
+	/**
+	 * set window bounds
+	 *
+	 * Set the "visible bounds" of a window from the user's
+	 * perspective. Client-side decorations often have invisible
+	 * portions like drop shadows which should be ignored for the
+	 * purposes of aligning, placing and constraining windows.
+	 *
+	 * The bounds are double buffered, and will be applied at the time
+	 * wl_surface.commit of the corresponding wl_surface is called.
+	 *
+	 * Once the bounds are set, it is not possible to unset them, and
+	 * they will remain the same until set_bounds is called again, even
+	 * if a new sub- surface or buffer is attached.
+	 *
+	 * If never set, the value is the surface content bounds. This
+	 * updates dynamically on every commit.
+	 *
+	 * The bounds are relative to the given display. If the display is
+	 * invalid, they are assumed to be relative to the primary display.
+	 *
+	 * The width and height must be greater than zero.
+	 * @since 18
+	 */
+	void (*set_bounds)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   uint32_t display_id_hi,
+			   uint32_t display_id_lo,
+			   int32_t x,
+			   int32_t y,
+			   int32_t width,
+			   int32_t height);
 };
 
 #define ZCR_REMOTE_SURFACE_V1_CLOSE 0
@@ -1434,6 +1468,10 @@
  * @ingroup iface_zcr_remote_surface_v1
  */
 #define ZCR_REMOTE_SURFACE_V1_PIP_SINCE_VERSION 15
+/**
+ * @ingroup iface_zcr_remote_surface_v1
+ */
+#define ZCR_REMOTE_SURFACE_V1_SET_BOUNDS_SINCE_VERSION 18
 
 /**
  * @ingroup iface_zcr_remote_surface_v1
@@ -1485,9 +1523,9 @@
  * @param resource_ The client's resource
  */
 static inline void
-zcr_remote_surface_v1_send_bounds_changed(struct wl_resource *resource_, uint32_t workspace_id_hi, uint32_t workspace_id_lo, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t bounds_change_reason)
+zcr_remote_surface_v1_send_bounds_changed(struct wl_resource *resource_, uint32_t display_id_hi, uint32_t display_id_lo, int32_t x, int32_t y, int32_t width, int32_t height, uint32_t bounds_change_reason)
 {
-	wl_resource_post_event(resource_, ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGED, workspace_id_hi, workspace_id_lo, x, y, width, height, bounds_change_reason);
+	wl_resource_post_event(resource_, ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGED, display_id_hi, display_id_lo, x, y, width, height, bounds_change_reason);
 }
 
 /**
diff --git a/third_party/wayland-protocols/protocol/remote-shell-protocol.c b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
index c0d09551..cbb688a 100644
--- a/third_party/wayland-protocols/protocol/remote-shell-protocol.c
+++ b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.13.0 */
+/* Generated by wayland-scanner 1.14.0 */
 
 /*
  * Copyright 2016 The Chromium Authors.
@@ -74,7 +74,7 @@
 };
 
 WL_EXPORT const struct wl_interface zcr_remote_shell_v1_interface = {
-	"zcr_remote_shell_v1", 17,
+	"zcr_remote_shell_v1", 18,
 	4, zcr_remote_shell_v1_requests,
 	5, zcr_remote_shell_v1_events,
 };
@@ -121,6 +121,7 @@
 	{ "set_extra_title", "13s", types + 0 },
 	{ "set_orientation_lock", "14u", types + 0 },
 	{ "pip", "15", types + 0 },
+	{ "set_bounds", "18uuiiii", types + 0 },
 };
 
 static const struct wl_message zcr_remote_surface_v1_events[] = {
@@ -134,8 +135,8 @@
 };
 
 WL_EXPORT const struct wl_interface zcr_remote_surface_v1_interface = {
-	"zcr_remote_surface_v1", 15,
-	41, zcr_remote_surface_v1_requests,
+	"zcr_remote_surface_v1", 18,
+	42, zcr_remote_surface_v1_requests,
 	7, zcr_remote_surface_v1_events,
 };
 
diff --git a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
index ef9402df..be08b34 100644
--- a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
+++ b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
@@ -38,7 +38,7 @@
     reset.
   </description>
 
-  <interface name="zcr_remote_shell_v1" version="17">
+  <interface name="zcr_remote_shell_v1" version="18">
     <description summary="remote_shell">
       The global interface that allows clients to turn a wl_surface into a
       "real window" which is remotely managed but can be stacked, activated
@@ -195,7 +195,7 @@
     </request>
   </interface>
 
-  <interface name="zcr_remote_surface_v1" version="15">
+  <interface name="zcr_remote_surface_v1" version="18">
     <description summary="A desktop window">
       An interface that may be implemented by a wl_surface, for
       implementations that provide a desktop-style user interface
@@ -252,9 +252,9 @@
 
     <request name="set_window_geometry">
       <description summary="set the new window geometry">
-	The window geometry of a window is its "visible bounds" from the
-	user's perspective. Client-side decorations often have invisible
-	portions like drop-shadows which should be ignored for the
+	[Deprecated] The window geometry of a window is its "visible bounds"
+	from the user's perspective. Client-side decorations often have
+	invisible portions like drop-shadows which should be ignored for the
 	purposes of aligning, placing and constraining windows.
 
 	The window geometry is double buffered, and will be applied at the
@@ -671,8 +671,8 @@
 	The client may ignore move request depending on the state,
 	e.g, if it becomes resizable or other constrants.
       </description>
-      <arg name="workspace_id_hi" type="uint"/>
-      <arg name="workspace_id_lo" type="uint"/>
+      <arg name="display_id_hi" type="uint"/>
+      <arg name="display_id_lo" type="uint"/>
       <arg name="x" type="int"/>
       <arg name="y" type="int"/>
       <arg name="width" type="int"/>
@@ -903,6 +903,38 @@
       </description>
     </request>
 
+    <!-- Version 18 additions -->
+
+    <request name="set_bounds" since="18">
+      <description summary="set window bounds">
+	Set the "visible bounds" of a window from the user's perspective.
+	Client-side decorations often have invisible portions like drop shadows
+	which should be ignored for the purposes of aligning, placing and
+	constraining windows.
+
+	The bounds are double buffered, and will be applied at the
+	time wl_surface.commit of the corresponding wl_surface is called.
+
+	Once the bounds are set, it is not possible to unset them, and they will
+	remain the same until set_bounds is called again, even if a new sub-
+	surface or buffer is attached.
+
+	If never set, the value is the surface content bounds. This updates
+	dynamically on every commit.
+
+	The bounds are relative to the given display. If the display is invalid,
+	they are assumed to be relative to the primary display.
+
+	The width and height must be greater than zero.
+      </description>
+      <arg name="display_id_hi" type="uint"/>
+      <arg name="display_id_lo" type="uint"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
   </interface>
 
   <interface name="zcr_notification_surface_v1" version="16">
diff --git a/tools/android/audio_focus_grabber/OWNERS b/tools/android/audio_focus_grabber/OWNERS
index 5ad525b..a45c7a3 100644
--- a/tools/android/audio_focus_grabber/OWNERS
+++ b/tools/android/audio_focus_grabber/OWNERS
@@ -1 +1,2 @@
+mlamouri@chromium.org
 zqzhang@chromium.org
diff --git a/tools/battor_agent/BUILD.gn b/tools/battor_agent/BUILD.gn
deleted file mode 100644
index f1f9f17..0000000
--- a/tools/battor_agent/BUILD.gn
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-# Works only on desktop platforms.
-assert(is_win || is_linux || is_mac)
-
-executable("battor_agent") {
-  sources = [
-    "battor_agent_bin.cc",
-  ]
-  deps = [
-    ":battor_agent_lib",
-    "//base",
-    "//build/win:default_exe_manifest",
-  ]
-}
-
-source_set("battor_agent_lib") {
-  sources = [
-    "battor_agent.cc",
-    "battor_agent.h",
-    "battor_connection.cc",
-    "battor_connection.h",
-    "battor_connection_impl.cc",
-    "battor_connection_impl.h",
-    "battor_error.cc",
-    "battor_error.h",
-    "battor_finder.cc",
-    "battor_finder.h",
-    "battor_sample_converter.cc",
-    "battor_sample_converter.h",
-    "serial_utils.cc",
-    "serial_utils.h",
-  ]
-  deps = [
-    "//base",
-    "//device/serial",
-    "//mojo/public/cpp/bindings",
-    "//net",
-  ]
-}
-
-test("battor_agent_unittests") {
-  sources = [
-    "battor_agent_unittest.cc",
-    "battor_connection_impl_unittest.cc",
-    "battor_protocol_types_unittest.cc",
-    "battor_sample_converter_unittest.cc",
-    "serial_utils_unittest.cc",
-  ]
-  deps = [
-    ":battor_agent_lib",
-    "//base",
-    "//base/test:run_all_unittests",
-    "//base/test:test_support",
-    "//device/serial:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/tools/battor_agent/DEPS b/tools/battor_agent/DEPS
deleted file mode 100644
index 9866dab..0000000
--- a/tools/battor_agent/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
-  "+device/serial",
-  "+mojo/public",
-  "+net/base",
-  "+services/device/public/mojom",
-]
diff --git a/tools/battor_agent/OWNERS b/tools/battor_agent/OWNERS
deleted file mode 100644
index a90dd82..0000000
--- a/tools/battor_agent/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-charliea@chromium.org
-nednguyen@google.com
-zhenw@chromium.org
diff --git a/tools/battor_agent/README b/tools/battor_agent/README
deleted file mode 100644
index 3c0c2df..0000000
--- a/tools/battor_agent/README
+++ /dev/null
@@ -1,25 +0,0 @@
-BattOr Agent
-============
-
-The BattOr Agent is a C++ library that acts as a means of
-communicating with a BattOr. BattOrs is an external USB device,
-typically connected to the host, that's capable of recording
-accurate, high-frequency (2000Hz) power samples.
-
-The BattOr Agent accepts five high-level tracing commands:
-
-- **StartTracing**, which tells the BattOr to start collecting power
-samples.
-- **StopTracing**, which tells the BattOr to stop collecting power
-samples and return its trace log.
-- **SupportsExplicitClockSync**, which returns whether the BattOr is
-able to record clock sync markers in its own trace log.
-- **RecordClockSyncMarker**, which writes the specified string into the
-BattOr trace log. Because this string is accompanied by a BattOr tracing
-timestamp, we can use this as a way of correlating the BattOr timeline
-and the host computer's timeline.
-- **IssueClockSyncMarker**, which tells the BattOr to issue clock sync
-markers to all other tracing agents that it's connected to.
-
-For those calling the agent from non-C++ code, we also provide a thin
-binary wrapper around the C++ library.
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc
deleted file mode 100644
index abc54c2..0000000
--- a/tools/battor_agent/battor_agent.cc
+++ /dev/null
@@ -1,768 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#include "tools/battor_agent/battor_agent.h"
-
-#include <algorithm>
-#include <iomanip>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "tools/battor_agent/battor_connection_impl.h"
-#include "tools/battor_agent/battor_sample_converter.h"
-
-using base::StringPrintf;
-using std::vector;
-
-namespace battor {
-
-namespace {
-
-// The maximum number of times to retry a command.
-const uint8_t kMaxCommandAttempts = 10;
-
-// The maximum number of times to retry a sample frame.
-const uint8_t kMaxFrameAttempts = 10;
-
-// The amount of time we need to wait after recording a clock sync marker in
-// order to ensure that the sample we synced to doesn't get thrown out.
-const uint8_t kStopTracingClockSyncDelayMilliseconds = 100;
-
-// The number of seconds to wait before retrying a command.
-const uint16_t kCommandRetryDelaySeconds = 2;
-
-// The number of milliseconds to wait before retrying a sample frame.
-const uint16_t kFrameRetryDelayMilliseconds = 100;
-
-// The number of seconds allowed for a control message before timing out.
-const uint8_t kBattOrControlMessageTimeoutSeconds = 2;
-
-// Returns true if the specified vector of bytes decodes to a message that is an
-// ack for the specified control message type.
-bool IsAckOfControlCommand(BattOrMessageType message_type,
-                           BattOrControlMessageType control_message_type,
-                           const vector<char>& msg) {
-  if (message_type != BATTOR_MESSAGE_TYPE_CONTROL_ACK)
-    return false;
-
-  if (msg.size() != sizeof(BattOrControlMessageAck))
-    return false;
-
-  const BattOrControlMessageAck* ack =
-      reinterpret_cast<const BattOrControlMessageAck*>(msg.data());
-
-  if (ack->type != control_message_type)
-    return false;
-
-  return true;
-}
-
-// Attempts to decode the specified vector of bytes decodes to a valid EEPROM.
-// Returns the new EEPROM, or nullptr if unsuccessful.
-std::unique_ptr<BattOrEEPROM> ParseEEPROM(BattOrMessageType message_type,
-                                          const vector<char>& msg) {
-  if (message_type != BATTOR_MESSAGE_TYPE_CONTROL_ACK)
-    return nullptr;
-
-  if (msg.size() != sizeof(BattOrEEPROM))
-    return nullptr;
-
-  std::unique_ptr<BattOrEEPROM> eeprom(new BattOrEEPROM());
-  memcpy(eeprom.get(), msg.data(), sizeof(BattOrEEPROM));
-  return eeprom;
-}
-}  // namespace
-
-BattOrResults::BattOrResults() = default;
-
-BattOrResults::BattOrResults(std::string details,
-                             std::vector<float> power_samples_W,
-                             uint32_t sample_rate)
-    : details_(std::move(details)),
-      power_samples_W_(std::move(power_samples_W)),
-      sample_rate_(sample_rate) {}
-
-BattOrResults::BattOrResults(const BattOrResults&) = default;
-
-BattOrResults::~BattOrResults() = default;
-
-BattOrAgent::BattOrAgent(
-    const std::string& path,
-    Listener* listener,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
-    : connection_(new BattOrConnectionImpl(path, this, ui_thread_task_runner)),
-      tick_clock_(base::DefaultTickClock::GetInstance()),
-      listener_(listener),
-      last_action_(Action::INVALID),
-      command_(Command::INVALID),
-      next_sequence_number_(0),
-      num_command_attempts_(0),
-      num_frame_attempts_(0) {
-  // We don't care what sequence the constructor is called on - we only care
-  // that all of the other method invocations happen on the same sequence.
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-BattOrAgent::~BattOrAgent() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void BattOrAgent::StartTracing() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  connection_->LogSerial("Starting command StartTracing.");
-
-  // When tracing is restarted, all previous clock sync markers are invalid.
-  clock_sync_markers_.clear();
-  last_clock_sync_time_ = base::TimeTicks();
-
-  command_ = Command::START_TRACING;
-
-  if (connection_->IsOpen()) {
-    PerformAction(GetFirstAction(Command::START_TRACING));
-  } else {
-    PerformAction(Action::REQUEST_CONNECTION);
-  }
-}
-
-void BattOrAgent::StopTracing() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  connection_->LogSerial("Starting command StopTracing.");
-
-  command_ = Command::STOP_TRACING;
-
-  if (connection_->IsOpen()) {
-    PerformAction(GetFirstAction(Command::STOP_TRACING));
-  } else {
-    PerformAction(Action::REQUEST_CONNECTION);
-  }
-}
-
-void BattOrAgent::RecordClockSyncMarker(const std::string& marker) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  connection_->LogSerial("Starting command RecordClockSyncMarker.");
-
-  command_ = Command::RECORD_CLOCK_SYNC_MARKER;
-  pending_clock_sync_marker_ = marker;
-
-  if (connection_->IsOpen()) {
-    PerformAction(GetFirstAction(Command::RECORD_CLOCK_SYNC_MARKER));
-  } else {
-    PerformAction(Action::REQUEST_CONNECTION);
-  }
-}
-
-void BattOrAgent::GetFirmwareGitHash() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  connection_->LogSerial("Starting command GetFirmwareGitHash.");
-
-  command_ = Command::GET_FIRMWARE_GIT_HASH;
-
-  if (connection_->IsOpen()) {
-    PerformAction(GetFirstAction(Command::GET_FIRMWARE_GIT_HASH));
-  } else {
-    PerformAction(Action::REQUEST_CONNECTION);
-  }
-}
-
-void BattOrAgent::BeginConnect() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  connection_->Open();
-}
-
-void BattOrAgent::OnConnectionOpened(bool success) {
-  if (!success) {
-    CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED);
-    return;
-  }
-
-  PerformAction(Action::POST_CONNECT_FLUSH);
-}
-
-void BattOrAgent::OnConnectionFlushed(bool success) {
-  if (!success) {
-    CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED);
-    return;
-  }
-
-  if (last_action_ == Action::POST_CONNECT_FLUSH) {
-    PerformAction(GetFirstAction(command_));
-  } else if (last_action_ == Action::POST_READ_ERROR_FLUSH) {
-    base::TimeDelta request_samples_delay =
-        base::TimeDelta::FromMilliseconds(kFrameRetryDelayMilliseconds);
-    PerformDelayedAction(Action::SEND_SAMPLES_REQUEST, request_samples_delay);
-  } else {
-    NOTREACHED();
-  }
-}
-
-void BattOrAgent::OnBytesSent(bool success) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!success) {
-    CompleteCommand(BATTOR_ERROR_SEND_ERROR);
-    return;
-  }
-
-  switch (last_action_) {
-    case Action::SEND_INIT:
-      PerformAction(Action::READ_INIT_ACK);
-      return;
-    case Action::SEND_SET_GAIN:
-      PerformAction(Action::READ_SET_GAIN_ACK);
-      return;
-    case Action::SEND_START_TRACING:
-      PerformAction(Action::READ_START_TRACING_ACK);
-      return;
-    case Action::SEND_EEPROM_REQUEST:
-      PerformAction(Action::READ_EEPROM);
-      return;
-    case Action::SEND_SAMPLES_REQUEST:
-      if (next_sequence_number_ == 0)
-        PerformAction(Action::READ_CALIBRATION_FRAME);
-      else
-        PerformAction(Action::READ_DATA_FRAME);
-      return;
-    case Action::SEND_CURRENT_SAMPLE_REQUEST:
-      PerformAction(Action::READ_CURRENT_SAMPLE);
-      return;
-    case Action::SEND_GIT_HASH_REQUEST:
-      PerformAction(Action::READ_GIT_HASH);
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-}
-
-void BattOrAgent::OnMessageRead(bool success,
-                                BattOrMessageType type,
-                                std::unique_ptr<vector<char>> bytes) {
-  timeout_callback_.Cancel();
-
-  if (!success) {
-    switch (last_action_) {
-      case Action::READ_GIT_HASH:
-      case Action::READ_INIT_ACK:
-      case Action::READ_SET_GAIN_ACK:
-      case Action::READ_START_TRACING_ACK:
-      case Action::READ_EEPROM:
-        RetryCommand();
-        return;
-
-      case Action::READ_CALIBRATION_FRAME:
-      case Action::READ_DATA_FRAME:
-        RetryFrame();
-        return;
-
-      case Action::READ_CURRENT_SAMPLE:
-        CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR);
-        return;
-
-      default:
-        NOTREACHED();
-        return;
-    }
-  }
-
-  switch (last_action_) {
-    case Action::READ_INIT_ACK:
-      if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT,
-                                 *bytes)) {
-        RetryCommand();
-        return;
-      }
-
-      switch (command_) {
-        case Command::START_TRACING:
-          PerformAction(Action::SEND_SET_GAIN);
-          return;
-        default:
-          NOTREACHED();
-          return;
-      }
-
-    case Action::READ_SET_GAIN_ACK:
-      if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN,
-                                 *bytes)) {
-        RetryCommand();
-        return;
-      }
-
-      PerformAction(Action::SEND_START_TRACING);
-      return;
-
-    case Action::READ_START_TRACING_ACK:
-      if (!IsAckOfControlCommand(
-              type, BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, *bytes)) {
-        RetryCommand();
-        return;
-      }
-
-      CompleteCommand(BATTOR_ERROR_NONE);
-      return;
-
-    case Action::READ_EEPROM: {
-      battor_eeprom_ = ParseEEPROM(type, *bytes);
-      if (!battor_eeprom_) {
-        RetryCommand();
-        return;
-      }
-
-      // Make sure that we don't request samples until a safe amount of time has
-      // elapsed since recording the last clock sync marker: we need to ensure
-      // that the sample we synced to doesn't get thrown out.
-      base::TimeTicks min_request_samples_time =
-          last_clock_sync_time_ + base::TimeDelta::FromMilliseconds(
-                                      kStopTracingClockSyncDelayMilliseconds);
-      base::TimeDelta request_samples_delay =
-          std::max(min_request_samples_time - tick_clock_->NowTicks(),
-                   base::TimeDelta());
-
-      num_frame_attempts_ = 1;
-      PerformDelayedAction(Action::SEND_SAMPLES_REQUEST, request_samples_delay);
-      return;
-    }
-    case Action::READ_CALIBRATION_FRAME: {
-      BattOrFrameHeader frame_header;
-      if (!ParseSampleFrame(type, *bytes, next_sequence_number_, &frame_header,
-                            &calibration_frame_)) {
-        RetryFrame();
-        return;
-      }
-
-      // Make sure that the calibration frame has actual samples in it.
-      if (calibration_frame_.empty()) {
-        CompleteCommand(BATTOR_ERROR_FILE_NOT_FOUND);
-        return;
-      }
-
-      next_sequence_number_++;
-      num_frame_attempts_ = 1;
-      PerformAction(Action::SEND_SAMPLES_REQUEST);
-      return;
-    }
-
-    case Action::READ_DATA_FRAME: {
-      BattOrFrameHeader frame_header;
-      vector<RawBattOrSample> frame;
-      if (!ParseSampleFrame(type, *bytes, next_sequence_number_, &frame_header,
-                            &frame)) {
-        RetryFrame();
-        return;
-      }
-
-      // Check for the empty frame the BattOr uses to indicate it's done
-      // streaming samples.
-      if (frame.empty()) {
-        CompleteCommand(BATTOR_ERROR_NONE);
-        return;
-      }
-
-      samples_.insert(samples_.end(), frame.begin(), frame.end());
-
-      next_sequence_number_++;
-      num_frame_attempts_ = 1;
-      PerformAction(Action::SEND_SAMPLES_REQUEST);
-      return;
-    }
-
-    case Action::READ_CURRENT_SAMPLE:
-      if (type != BATTOR_MESSAGE_TYPE_CONTROL_ACK ||
-          bytes->size() != sizeof(uint32_t)) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
-        return;
-      }
-
-      uint32_t sample_num;
-      memcpy(&sample_num, bytes->data(), sizeof(uint32_t));
-      clock_sync_markers_[sample_num] = pending_clock_sync_marker_;
-      last_clock_sync_time_ = tick_clock_->NowTicks();
-      CompleteCommand(BATTOR_ERROR_NONE);
-      return;
-
-    case Action::READ_GIT_HASH:
-      if (type != BATTOR_MESSAGE_TYPE_CONTROL_ACK) {
-        RetryCommand();
-        return;
-      }
-
-      firmware_git_hash_ = std::string(bytes->begin(), bytes->end());
-      CompleteCommand(BATTOR_ERROR_NONE);
-      return;
-
-    default:
-      NOTREACHED();
-      return;
-  }
-}
-
-void BattOrAgent::PerformAction(Action action) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  last_action_ = action;
-
-  switch (action) {
-    case Action::REQUEST_CONNECTION:
-      BeginConnect();
-      return;
-    case Action::POST_CONNECT_FLUSH:
-    case Action::POST_READ_ERROR_FLUSH:
-      connection_->Flush();
-      return;
-    // The following actions are required for StartTracing:
-    case Action::SEND_INIT:
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0);
-      return;
-    case Action::READ_INIT_ACK:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-    case Action::SEND_SET_GAIN:
-      // Set the BattOr's gain. Setting the gain tells the BattOr the range of
-      // power measurements that we expect to see.
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, BATTOR_GAIN_LOW,
-                         0);
-      return;
-    case Action::READ_SET_GAIN_ACK:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-    case Action::SEND_START_TRACING:
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0, 0);
-      return;
-    case Action::READ_START_TRACING_ACK:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-    // The following actions are required for StopTracing:
-    case Action::SEND_EEPROM_REQUEST:
-      // Read the BattOr's EEPROM to get calibration information that's required
-      // to convert the raw samples to accurate ones.
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_READ_EEPROM,
-                         sizeof(BattOrEEPROM), 0);
-      return;
-    case Action::READ_EEPROM:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-    case Action::SEND_SAMPLES_REQUEST:
-      // Send a request to the BattOr to tell it to start streaming the samples
-      // that it's stored on its SD card over the serial connection.
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0,
-                         next_sequence_number_);
-      return;
-    case Action::READ_CALIBRATION_FRAME:
-      // Data frames are numbered starting at zero and counting up by one each
-      // data frame. We keep track of the next frame sequence number we expect
-      // to see to ensure we don't miss any data.
-      next_sequence_number_ = 0;
-
-      // Clear stored samples from prior attempts to read sample frames.
-      samples_.clear();
-      calibration_frame_.clear();
-      FALLTHROUGH;
-    case Action::READ_DATA_FRAME:
-      // The first frame sent back from the BattOr contains voltage and current
-      // data that excludes whatever device is being measured from the
-      // circuit. We use this first frame to establish a baseline voltage and
-      // current.
-      //
-      // All further frames contain real (but uncalibrated) voltage and current
-      // data.
-      SetActionTimeout(kBattOrControlMessageTimeoutSeconds);
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES);
-      return;
-
-    // The following actions are required for RecordClockSyncMarker:
-    case Action::SEND_CURRENT_SAMPLE_REQUEST:
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_READ_SAMPLE_COUNT, 0, 0);
-      return;
-    case Action::READ_CURRENT_SAMPLE:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-
-    case Action::SEND_GIT_HASH_REQUEST:
-      SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_GET_FIRMWARE_GIT_HASH, 0,
-                         0);
-      return;
-
-    case Action::READ_GIT_HASH:
-      connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
-      return;
-
-    case Action::INVALID:
-      NOTREACHED();
-      return;
-  }
-}
-
-void BattOrAgent::PerformDelayedAction(Action action, base::TimeDelta delay) {
-  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&BattOrAgent::PerformAction, AsWeakPtr(), action),
-      delay);
-}
-
-void BattOrAgent::OnActionTimeout() {
-  switch (last_action_) {
-    case Action::READ_INIT_ACK:
-    case Action::READ_SET_GAIN_ACK:
-    case Action::READ_START_TRACING_ACK:
-    case Action::READ_EEPROM:
-    case Action::READ_CALIBRATION_FRAME:
-    case Action::READ_DATA_FRAME:
-    case Action::READ_GIT_HASH:
-      connection_->CancelReadMessage();
-      return;
-
-    default:
-      CompleteCommand(BATTOR_ERROR_TIMEOUT);
-      timeout_callback_.Cancel();
-  }
-}
-
-void BattOrAgent::SendControlMessage(BattOrControlMessageType type,
-                                     uint16_t param1,
-                                     uint16_t param2) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  SetActionTimeout(kBattOrControlMessageTimeoutSeconds);
-
-  BattOrControlMessage msg{type, param1, param2};
-  connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg));
-}
-
-// Returns true if the specified vector of bytes decodes to a valid BattOr
-// samples frame. The frame header and samples are returned via the frame_header
-// and samples paramaters.
-bool BattOrAgent::ParseSampleFrame(BattOrMessageType type,
-                                   const vector<char>& msg,
-                                   uint32_t expected_sequence_number,
-                                   BattOrFrameHeader* frame_header,
-                                   vector<RawBattOrSample>* samples) {
-  if (type != BATTOR_MESSAGE_TYPE_SAMPLES) {
-    connection_->LogSerial(
-        StringPrintf("ParseSampleFrame failed due to unexpected message type "
-                     "number (wanted BATTOR_MESSAGE_TYPE_SAMPLES, but got %d).",
-                     type));
-    return false;
-  }
-
-  // Each frame should contain a header and an integer number of BattOr samples.
-  if ((msg.size() - sizeof(BattOrFrameHeader)) % sizeof(RawBattOrSample) != 0) {
-    connection_->LogSerial(
-        "ParseSampleFrame failed due to containing a noninteger number of "
-        "BattOr samples.");
-    return false;
-  }
-
-  // The first bytes in the frame contain the frame header.
-  const char* frame_ptr = reinterpret_cast<const char*>(msg.data());
-  memcpy(frame_header, frame_ptr, sizeof(BattOrFrameHeader));
-  frame_ptr += sizeof(BattOrFrameHeader);
-
-  if (frame_header->sequence_number != expected_sequence_number) {
-    connection_->LogSerial(
-        StringPrintf("ParseSampleFrame failed due to unexpected sequence "
-                     "number (wanted %d, but got %d).",
-                     expected_sequence_number, frame_header->sequence_number));
-    return false;
-  }
-
-  size_t remaining_bytes = msg.size() - sizeof(BattOrFrameHeader);
-  if (remaining_bytes != frame_header->length) {
-    connection_->LogSerial(StringPrintf(
-        "ParseSampleFrame failed due to to a mismatch between the length of "
-        "the frame as stated in the frame header and the actual length of the "
-        "frame (frame header %d, actual length %zu).",
-        frame_header->length, remaining_bytes));
-    return false;
-  }
-
-  samples->resize(remaining_bytes / sizeof(RawBattOrSample));
-  memcpy(samples->data(), frame_ptr, remaining_bytes);
-
-  return true;
-}
-
-void BattOrAgent::RetryCommand() {
-  if (++num_command_attempts_ >= kMaxCommandAttempts) {
-    connection_->LogSerial(StringPrintf(
-        "Exhausted command retry attempts (would have been attempt %d of %d).",
-        num_command_attempts_ + 1, kMaxCommandAttempts));
-    CompleteCommand(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES);
-    return;
-  }
-
-  connection_->LogSerial(StringPrintf("Retrying command (attempt %d of %d).",
-                                      num_command_attempts_ + 1,
-                                      kMaxCommandAttempts));
-
-  // Restart the serial connection to guarantee that the connection gets flushed
-  // before retrying the command.
-  connection_->Close();
-
-  // Failed to read response to message, retry current command.
-  base::Callback<void()> next_command;
-  switch (command_) {
-    case Command::START_TRACING:
-      next_command = base::Bind(&BattOrAgent::StartTracing, AsWeakPtr());
-      break;
-    case Command::STOP_TRACING:
-      next_command = base::Bind(&BattOrAgent::StopTracing, AsWeakPtr());
-      break;
-    case Command::GET_FIRMWARE_GIT_HASH:
-      next_command = base::Bind(&BattOrAgent::GetFirmwareGitHash, AsWeakPtr());
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, next_command,
-      base::TimeDelta::FromSeconds(kCommandRetryDelaySeconds));
-}
-
-void BattOrAgent::RetryFrame() {
-  if (++num_frame_attempts_ > kMaxFrameAttempts) {
-    connection_->LogSerial(StringPrintf(
-        "Exhausted frame retry attempts (would have been attempt %d of %d).",
-        num_frame_attempts_, kMaxFrameAttempts));
-    CompleteCommand(BATTOR_ERROR_TOO_MANY_FRAME_RETRIES);
-    return;
-  }
-
-  connection_->LogSerial(StringPrintf("Retrying frame (attempt %d of %d).",
-                                      num_frame_attempts_,
-                                      kMaxFrameAttempts));
-
-  PerformAction(Action::POST_READ_ERROR_FLUSH);
-}
-
-void BattOrAgent::CompleteCommand(BattOrError error) {
-  connection_->LogSerial(
-      StringPrintf("Completing command with error code: %d.", error));
-
-  switch (command_) {
-    case Command::START_TRACING:
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&Listener::OnStartTracingComplete,
-                                base::Unretained(listener_), error));
-      break;
-    case Command::STOP_TRACING:
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(&Listener::OnStopTracingComplete,
-                     base::Unretained(listener_), SamplesToResults(), error));
-      break;
-    case Command::RECORD_CLOCK_SYNC_MARKER:
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&Listener::OnRecordClockSyncMarkerComplete,
-                                base::Unretained(listener_), error));
-      break;
-    case Command::GET_FIRMWARE_GIT_HASH:
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(&Listener::OnGetFirmwareGitHashComplete,
-                     base::Unretained(listener_), firmware_git_hash_, error));
-      break;
-    case Command::INVALID:
-      NOTREACHED();
-      return;
-  }
-
-  last_action_ = Action::INVALID;
-  command_ = Command::INVALID;
-  pending_clock_sync_marker_.clear();
-  battor_eeprom_.reset();
-  calibration_frame_.clear();
-  samples_.clear();
-  next_sequence_number_ = 0;
-  num_command_attempts_ = 0;
-}
-
-BattOrResults BattOrAgent::SamplesToResults() {
-  if (calibration_frame_.empty() || samples_.empty() || !battor_eeprom_)
-    return BattOrResults();
-
-  BattOrSampleConverter converter(*battor_eeprom_, calibration_frame_);
-
-  std::stringstream trace_stream;
-  trace_stream << std::fixed;
-
-  // Create a header that indicates the BattOr's parameters for these samples.
-  BattOrSample min_sample = converter.MinSample();
-  BattOrSample max_sample = converter.MaxSample();
-  trace_stream << "# BattOr" << std::endl
-               << std::setprecision(1) << "# voltage_range ["
-               << min_sample.voltage_mV << ", " << max_sample.voltage_mV
-               << "] mV" << std::endl
-               << "# current_range [" << min_sample.current_mA << ", "
-               << max_sample.current_mA << "] mA" << std::endl
-               << "# sample_rate " << battor_eeprom_->sd_sample_rate << " Hz"
-               << ", gain " << battor_eeprom_->low_gain << "x" << std::endl;
-
-  // Create a string representation of the BattOr samples.
-  for (size_t i = 0; i < samples_.size(); i++) {
-    BattOrSample sample = converter.ToSample(samples_[i], i);
-    trace_stream << std::setprecision(2) << sample.time_ms << " "
-                 << std::setprecision(1) << sample.current_mA << " "
-                 << sample.voltage_mV;
-
-    // If there's a clock sync marker for the current sample, print it.
-    auto clock_sync_marker = clock_sync_markers_.find(
-        static_cast<uint32_t>(calibration_frame_.size() + i));
-    if (clock_sync_marker != clock_sync_markers_.end())
-      trace_stream << " <" << clock_sync_marker->second << ">";
-
-    trace_stream << std::endl;
-  }
-
-  for (auto it = clock_sync_markers_.begin(); it != clock_sync_markers_.end();
-       ++it) {
-    size_t total_sample_count = calibration_frame_.size() + samples_.size();
-    if (it->first >= total_sample_count) {
-      connection_->LogSerial(StringPrintf(
-          "Clock sync occurred at a sample not included in the result (clock "
-          "sync sample index: %d, total sample count: %zu).",
-          it->first, total_sample_count));
-    }
-  }
-
-  // Convert to a vector of power in watts.
-  std::vector<float> samples(samples_.size());
-  for (size_t i = 0; i < samples_.size(); i++)
-    samples[i] = converter.ToWatts(samples_[i]);
-
-  return BattOrResults(trace_stream.str(), samples,
-                       battor_eeprom_->sd_sample_rate);
-}
-
-void BattOrAgent::SetActionTimeout(uint16_t timeout_seconds) {
-  timeout_callback_.Reset(
-      base::Bind(&BattOrAgent::OnActionTimeout, AsWeakPtr()));
-  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, timeout_callback_.callback(),
-      base::TimeDelta::FromSeconds(timeout_seconds));
-}
-
-BattOrAgent::Action BattOrAgent::GetFirstAction(BattOrAgent::Command command) {
-  switch (command_) {
-    case Command::START_TRACING:
-      return Action::SEND_INIT;
-    case Command::STOP_TRACING:
-      return Action::SEND_EEPROM_REQUEST;
-    case Command::RECORD_CLOCK_SYNC_MARKER:
-      return Action::SEND_CURRENT_SAMPLE_REQUEST;
-    case Command::GET_FIRMWARE_GIT_HASH:
-      return Action::SEND_GIT_HASH_REQUEST;
-    case Command::INVALID:
-      NOTREACHED();
-  }
-
-  return Action::INVALID;
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h
deleted file mode 100644
index d33b8e0..0000000
--- a/tools/battor_agent/battor_agent.h
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_
-
-#include <map>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/default_tick_clock.h"
-#include "tools/battor_agent/battor_connection.h"
-#include "tools/battor_agent/battor_error.h"
-
-namespace battor {
-
-// A BattOrResults object contains the results of BattOr tracing, including a
-// summary and sample data in watts.
-class BattOrResults {
- public:
-  BattOrResults();
-  BattOrResults(std::string details,
-                std::vector<float> power_samples_W,
-                uint32_t sample_rate);
-  BattOrResults(const BattOrResults&);
-  ~BattOrResults();
-
-  // Get a detailed textual representation of the data recorded.
-  const std::string& ToString() const { return details_; }
-  // Returns a vector of power samples (in watts).
-  const std::vector<float>& GetPowerSamples() const { return power_samples_W_; }
-  uint32_t GetSampleRate() const { return sample_rate_; }
-
- private:
-  std::string details_;
-  std::vector<float> power_samples_W_;
-  uint32_t sample_rate_ = 0;
-};
-
-// A BattOrAgent is a class used to asynchronously communicate with a BattOr for
-// the purpose of collecting power samples. A BattOr is an external USB device
-// that's capable of recording accurate, high-frequency (2000Hz) power samples.
-//
-// The serial connection is automatically opened when the first command
-// (e.g. StartTracing(), StopTracing(), etc.) is issued, and automatically
-// closed when either StopTracing() or the destructor is called. For Telemetry,
-// this means that the connection must be reinitialized for every command that's
-// issued because a new BattOrAgent is constructed. For Chromium, we use the
-// same BattOrAgent for multiple commands and thus avoid having to reinitialize
-// the serial connection.
-//
-// This class is NOT thread safe. Any interactions with this class that involve
-// IO (i.e. any interactions that require a callback) must be done from the
-// same IO thread, which must also have a running MessageLoop.
-class BattOrAgent : public BattOrConnection::Listener,
-                    public base::SupportsWeakPtr<BattOrAgent> {
- public:
-  // The listener interface that must be implemented in order to interact with
-  // the BattOrAgent.
-  class Listener {
-   public:
-    virtual void OnStartTracingComplete(BattOrError error) = 0;
-    virtual void OnStopTracingComplete(const BattOrResults& trace,
-                                       BattOrError error) = 0;
-    virtual void OnRecordClockSyncMarkerComplete(BattOrError error) = 0;
-    virtual void OnGetFirmwareGitHashComplete(const std::string& version,
-                                              BattOrError error) = 0;
-  };
-
-  BattOrAgent(
-      const std::string& path,
-      Listener* listener,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
-  virtual ~BattOrAgent();
-
-  void StartTracing();
-  void StopTracing();
-  void RecordClockSyncMarker(const std::string& marker);
-  void GetFirmwareGitHash();
-
-  // Returns whether the BattOr is able to record clock sync markers in its own
-  // trace log.
-  static bool SupportsExplicitClockSync() { return true; }
-
-  // BattOrConnection::Listener implementation.
-  void OnConnectionOpened(bool success) override;
-  void OnConnectionFlushed(bool success) override;
-  void OnBytesSent(bool success) override;
-  void OnMessageRead(bool success,
-                     BattOrMessageType type,
-                     std::unique_ptr<std::vector<char>> bytes) override;
-
- protected:
-  // The connection that knows how to communicate with the BattOr in terms of
-  // protocol primitives. This is protected so that it can be replaced with a
-  // fake in testing.
-  std::unique_ptr<BattOrConnection> connection_;
-
-  // A source of TimeTicks. Protected so that it can be faked in testing.
-  const base::TickClock* tick_clock_;
-
-  // Timeout for when an action isn't completed within the allotted time. This
-  // is virtual and protected so that timeouts can be disabled in testing. The
-  // testing task runner that runs delayed tasks immediately deals poorly with
-  // timeouts posted as future tasks.
-  virtual void OnActionTimeout();
-
- private:
-  enum class Command {
-    INVALID,
-    START_TRACING,
-    STOP_TRACING,
-    RECORD_CLOCK_SYNC_MARKER,
-    GET_FIRMWARE_GIT_HASH,
-  };
-
-  enum class Action {
-    INVALID,
-
-    // Actions required to connect to a BattOr.
-    REQUEST_CONNECTION,
-    POST_CONNECT_FLUSH,
-
-    // Actions required for starting tracing.
-    SEND_INIT,
-    READ_INIT_ACK,
-    SEND_SET_GAIN,
-    READ_SET_GAIN_ACK,
-    SEND_START_TRACING,
-    READ_START_TRACING_ACK,
-
-    // Actions required for stopping tracing.
-    SEND_EEPROM_REQUEST,
-    READ_EEPROM,
-    SEND_SAMPLES_REQUEST,
-    READ_CALIBRATION_FRAME,
-    READ_DATA_FRAME,
-    POST_READ_ERROR_FLUSH,
-
-    // Actions required for recording a clock sync marker.
-    SEND_CURRENT_SAMPLE_REQUEST,
-    READ_CURRENT_SAMPLE,
-
-    // Actions required for returning firmware git hash.
-    SEND_GIT_HASH_REQUEST,
-    READ_GIT_HASH,
-  };
-
-  // Performs an action.
-  void PerformAction(Action action);
-  // Performs an action after a delay.
-  void PerformDelayedAction(Action action, base::TimeDelta delay);
-
-  // Requests a connection to the BattOr.
-  void BeginConnect();
-
-  // Sends a control message over the connection.
-  void SendControlMessage(BattOrControlMessageType type,
-                          uint16_t param1,
-                          uint16_t param2);
-
-  bool ParseSampleFrame(BattOrMessageType type,
-                        const std::vector<char>& msg,
-                        uint32_t expected_sequence_number,
-                        BattOrFrameHeader* frame_header,
-                        std::vector<RawBattOrSample>* samples);
-
-  // Retry the last command.
-  void RetryCommand();
-
-  // Retry the last sample frame.
-  void RetryFrame();
-
-  // Completes the command with the specified error.
-  void CompleteCommand(BattOrError error);
-
-  // Returns a formatted version of samples_ with timestamps and real units.
-  BattOrResults SamplesToResults();
-
-  // Sets and restarts the action timeout timer.
-  void SetActionTimeout(uint16_t timeout_seconds);
-
-  // Returns the first action for the specified command (excluding connection
-  // actions).
-  Action GetFirstAction(Command command);
-
-  // The listener that handles the commands' results. It must outlive the agent.
-  Listener* listener_;
-
-  // The last action executed by the agent. This should only be updated in
-  // PerformAction().
-  Action last_action_;
-
-  // The tracing command currently being executed by the agent.
-  Command command_;
-
-  // A map from the sample number (including samples from the calibration frame)
-  // to the ID of the clock sync marker that is associated with that sample
-  // number. If we ever have to store a large number of these, consider using an
-  // unordered map.
-  std::map<uint32_t, std::string> clock_sync_markers_;
-
-  // The clock sync marker being recorded (if we're currently recording one).
-  std::string pending_clock_sync_marker_;
-
-  // The time at which the last clock sync marker was recorded.
-  base::TimeTicks last_clock_sync_time_;
-
-  // The BattOr's EEPROM (which is required for calibration).
-  std::unique_ptr<BattOrEEPROM> battor_eeprom_;
-
-  // The first frame (required for calibration).
-  std::vector<RawBattOrSample> calibration_frame_;
-
-  // The actual data samples recorded.
-  std::vector<RawBattOrSample> samples_;
-
-  // The expected sequence number of the next frame. We use this to ensure that
-  // we receive frames in order.
-  uint32_t next_sequence_number_;
-
-  // The number of times we've attempted a command.
-  uint8_t num_command_attempts_;
-
-  // The number of times we've attempted receiving a frame.
-  uint8_t num_frame_attempts_;
-
-  // The timeout that's run when an action times out.
-  base::CancelableClosure timeout_callback_;
-
-  // The git hash of the BattOr firmware.
-  std::string firmware_git_hash_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(BattOrAgent);
-};
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc
deleted file mode 100644
index d37b2035..0000000
--- a/tools/battor_agent/battor_agent_bin.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file provides a thin binary wrapper around the BattOr Agent
-// library. This binary wrapper provides a means for non-C++ tracing
-// controllers, such as Telemetry and Android Systrace, to issue high-level
-// tracing commands to the BattOr through an interactive shell.
-//
-// Example usage of how an external trace controller might use this binary:
-//
-// 1) Telemetry's PowerTracingAgent is told to start recording power samples
-// 2) PowerTracingAgent opens up a BattOr agent binary subprocess
-// 3) PowerTracingAgent sends the subprocess the StartTracing message via
-//    STDIN
-// 4) PowerTracingAgent waits for the subprocess to write a line to STDOUT
-//    ('Done.' if successful, some error message otherwise)
-// 5) If the last command was successful, PowerTracingAgent waits for the
-//    duration of the trace
-// 6) When the tracing should end, PowerTracingAgent records the clock sync
-//    start timestamp and sends the subprocess the
-//    'RecordClockSyncMark <marker>' message via STDIN.
-// 7) PowerTracingAgent waits for the subprocess to write a line to STDOUT
-//    ('Done.' if successful, some error message otherwise)
-// 8) If the last command was successful, PowerTracingAgent records the clock
-//    sync end timestamp and sends the subprocess the StopTracing message via
-//    STDIN
-// 9) PowerTracingAgent continues to read trace output lines from STDOUT until
-//    the binary exits with an exit code of 1 (indicating failure) or the
-//    'Done.' line is printed to STDOUT, signaling the last line of the trace
-// 10) PowerTracingAgent returns the battery trace to the Telemetry trace
-//     controller
-
-#include <stdint.h>
-
-#include <fstream>
-#include <iomanip>
-#include <iostream>
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/task_scheduler/task_scheduler.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "tools/battor_agent/battor_agent.h"
-#include "tools/battor_agent/battor_error.h"
-#include "tools/battor_agent/battor_finder.h"
-
-using std::endl;
-
-namespace battor {
-
-namespace {
-
-const char kIoThreadName[] = "BattOr IO Thread";
-
-const char kUsage[] =
-    "Start the battor_agent shell with:\n"
-    "\n"
-    "  battor_agent <switches>\n"
-    "\n"
-    "Switches: \n"
-    "  --battor-path=<path> Uses the specified BattOr path.\n"
-    "  --interactive Enables interactive power profiling."
-    "\n"
-    "Once in the shell, you can issue the following commands:\n"
-    "\n"
-    "  StartTracing\n"
-    "  StopTracing <optional file path>\n"
-    "  SupportsExplicitClockSync\n"
-    "  RecordClockSyncMarker <marker>\n"
-    "  GetFirmwareGitHash\n"
-    "  Exit\n"
-    "  Help\n"
-    "\n";
-
-// The command line switch used to enable interactive mode where starting and
-// stopping is easily toggled.
-const char kInteractiveSwitch[] = "interactive";
-
-void PrintSupportsExplicitClockSync() {
-  std::cout << BattOrAgent::SupportsExplicitClockSync() << endl;
-}
-
-// Logs the error and exits with an error code.
-void HandleError(battor::BattOrError error) {
-  if (error != BATTOR_ERROR_NONE)
-    LOG(FATAL) << "Fatal error when communicating with the BattOr: "
-               << BattOrErrorToString(error);
-}
-
-// Prints an error message and exits due to a required thread failing to start.
-void ExitFromThreadStartFailure(const std::string& thread_name) {
-  LOG(FATAL) << "Failed to start " << thread_name;
-}
-
-std::vector<std::string> TokenizeString(std::string cmd) {
-  base::StringTokenizer tokenizer(cmd, " ");
-  std::vector<std::string> tokens;
-  while (tokenizer.GetNext())
-    tokens.push_back(tokenizer.token());
-  return tokens;
-}
-
-}  // namespace
-
-// Wrapper class containing all state necessary for an independent binary to
-// use a BattOrAgent to communicate with a BattOr.
-class BattOrAgentBin : public BattOrAgent::Listener {
- public:
-  BattOrAgentBin() : io_thread_(kIoThreadName) {}
-
-  ~BattOrAgentBin() { DCHECK(!agent_); }
-
-  // Starts the interactive BattOr agent shell and eventually returns an exit
-  // code.
-  int Run(int argc, char* argv[]) {
-    // If we don't have any BattOr to use, exit.
-    std::string path = BattOrFinder::FindBattOr();
-    if (path.empty()) {
-      std::cout << "Unable to find a BattOr." << endl;
-#if defined(OS_WIN)
-      std::cout << "Try \"--battor-path=<path>\" to specify the COM port where "
-                   "the BattOr can be found, typically COM3."
-                << endl;
-#endif
-      exit(1);
-    }
-
-    SetUp(path);
-
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(kInteractiveSwitch)) {
-      interactive_ = true;
-      std::cout << "Type <Enter> to toggle tracing, type Exit or Ctrl+C "
-                   "to quit, or Help for help."
-                << endl;
-    }
-
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgentBin::RunNextCommand, base::Unretained(this)));
-    ui_thread_run_loop_.Run();
-
-    TearDown();
-    return 0;
-  }
-
-  // Performs any setup necessary for the BattOr binary to run.
-  void SetUp(const std::string& path) {
-    base::Thread::Options io_thread_options;
-    io_thread_options.message_loop_type = base::MessageLoopForIO::TYPE_IO;
-    if (!io_thread_.StartWithOptions(io_thread_options)) {
-      ExitFromThreadStartFailure(kIoThreadName);
-    }
-
-    // Block until the creation of the BattOrAgent is complete. This doesn't
-    // seem necessary because we're posting the creation to the IO thread
-    // before posting any commands, so we're guaranteed that the creation
-    // will happen first. However, the crashes that happen without this sync
-    // mechanism in place say otherwise.
-    base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                             base::WaitableEvent::InitialState::NOT_SIGNALED);
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgentBin::CreateAgent, base::Unretained(this), path,
-                   base::ThreadTaskRunnerHandle::Get(), &done));
-    done.Wait();
-  }
-
-  // Performs any cleanup necessary after the BattOr binary is done running.
-  void TearDown() {
-    base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                             base::WaitableEvent::InitialState::NOT_SIGNALED);
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&BattOrAgentBin::DeleteAgent,
-                              base::Unretained(this), &done));
-    done.Wait();
-  }
-
-  void RunNextCommand() {
-    std::string cmd;
-    std::getline(std::cin, cmd);
-
-    if (interactive_) {
-      if (cmd == "") {
-        cmd = is_tracing_ ? "StopTracing" : "StartTracing";
-        std::cout << cmd << endl;
-        is_tracing_ = !is_tracing_;
-      }
-    }
-
-    if (cmd == "StartTracing") {
-      StartTracing();
-    } else if (cmd.find("StopTracing") != std::string::npos) {
-      std::vector<std::string> tokens = TokenizeString(cmd);
-
-      if (tokens[0] != "StopTracing" || tokens.size() > 2) {
-        std::cout << "Invalid StopTracing command." << endl;
-        std::cout << kUsage << endl;
-        PostRunNextCommand();
-        return;
-      }
-
-      // tokens[1] contains the optional output file argument, which allows
-      // users to dump the trace to a file instead instead of to STDOUT.
-      std::string trace_output_file =
-          tokens.size() == 2 ? tokens[1] : std::string();
-
-      StopTracing(trace_output_file);
-      if (interactive_) {
-        PostRunNextCommand();
-      }
-    } else if (cmd == "SupportsExplicitClockSync") {
-      PrintSupportsExplicitClockSync();
-      PostRunNextCommand();
-    } else if (cmd.find("RecordClockSyncMarker") != std::string::npos) {
-      std::vector<std::string> tokens = TokenizeString(cmd);
-      if (tokens.size() != 2 || tokens[0] != "RecordClockSyncMarker") {
-        std::cout << "Invalid RecordClockSyncMarker command." << endl;
-        std::cout << kUsage << endl;
-        PostRunNextCommand();
-        return;
-      }
-
-      RecordClockSyncMarker(tokens[1]);
-    } else if (cmd == "GetFirmwareGitHash") {
-      GetFirmwareGitHash();
-      return;
-    } else if (cmd == "Exit" || std::cin.eof()) {
-      ui_thread_message_loop_.task_runner()->PostTask(
-          FROM_HERE, ui_thread_run_loop_.QuitClosure());
-    } else {
-      std::cout << kUsage << endl;
-      PostRunNextCommand();
-    }
-  }
-
-  void PostRunNextCommand() {
-    ui_thread_message_loop_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgentBin::RunNextCommand, base::Unretained(this)));
-  }
-
-  void GetFirmwareGitHash() {
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgent::GetFirmwareGitHash,
-                   base::Unretained(agent_.get())));
-  }
-
-  void OnGetFirmwareGitHashComplete(const std::string& firmware_git_hash,
-                                    BattOrError error) override {
-    if (error == BATTOR_ERROR_NONE)
-      std::cout << firmware_git_hash << endl;
-    else
-      HandleError(error);
-
-    PostRunNextCommand();
-  }
-
-  void StartTracing() {
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgent::StartTracing, base::Unretained(agent_.get())));
-  }
-
-  void OnStartTracingComplete(BattOrError error) override {
-    if (error == BATTOR_ERROR_NONE)
-      std::cout << "Done." << endl;
-    else
-      HandleError(error);
-
-    PostRunNextCommand();
-  }
-
-  void StopTracing(const std::string& trace_output_file) {
-    trace_output_file_ = trace_output_file;
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&BattOrAgent::StopTracing, base::Unretained(agent_.get())));
-  }
-
-  std::string BattOrResultsToSummary(const BattOrResults& results) {
-    const uint32_t samples_per_second = results.GetSampleRate();
-
-    // Print a summary of a BattOr trace. These summaries are intended for human
-    // consumption and are subject to change at any moment. The summary is
-    // printed when using interactive mode.
-    std::stringstream trace_summary;
-    // Display floating-point numbers without exponents, in a five-character
-    // field, with two digits of precision. ie;
-    // 12.39
-    //  8.40
-    trace_summary << std::fixed << std::setw(5) << std::setprecision(2);
-
-    // Scan through the sample data to summarize it. Report on average power and
-    // second-by-second power including min-second, median-second, and
-    // max-second.
-    double total_power = 0.0;
-    int num_seconds = 0;
-    std::vector<double> power_by_seconds;
-    const std::vector<float>& samples = results.GetPowerSamples();
-    for (size_t i = 0; i < samples.size(); i += samples_per_second) {
-      size_t loop_count = samples.size() - i;
-      if (loop_count > samples_per_second)
-        loop_count = samples_per_second;
-
-      double second_power = 0.0;
-      for (size_t j = i; j < i + loop_count; ++j) {
-        total_power += samples[i];
-        second_power += samples[i];
-      }
-
-      // Print/store results for full seconds.
-      if (loop_count == samples_per_second) {
-        // Calculate power for one second in watts.
-        second_power /= samples_per_second;
-        trace_summary << "Second " << std::setw(2) << num_seconds
-                      << " average power: " << std::setw(5) << second_power
-                      << " W" << std::endl;
-        ++num_seconds;
-        power_by_seconds.push_back(second_power);
-      }
-    }
-    // Calculate average power in watts.
-    const double average_power_W = total_power / samples.size();
-    const double duration_sec =
-        static_cast<double>(samples.size()) / samples_per_second;
-    trace_summary << "Average power over " << duration_sec
-                  << " s : " << average_power_W << " W" << std::endl;
-    std::sort(power_by_seconds.begin(), power_by_seconds.end());
-    if (power_by_seconds.size() >= 3) {
-      trace_summary << "Summary of power-by-seconds:" << std::endl
-                    << "Minimum: " << power_by_seconds[0] << std::endl
-                    << "Median:  "
-                    << power_by_seconds[power_by_seconds.size() / 2]
-                    << std::endl
-                    << "Maximum: "
-                    << power_by_seconds[power_by_seconds.size() - 1]
-                    << std::endl;
-    } else {
-      trace_summary << "Too short a trace to generate per-second summary.";
-    }
-
-    return trace_summary.str();
-  }
-
-  void OnStopTracingComplete(const BattOrResults& results,
-                             BattOrError error) override {
-    if (error == BATTOR_ERROR_NONE) {
-      std::string output_file = trace_output_file_;
-      if (trace_output_file_.empty()) {
-        // Save the detailed results in case they are needed.
-        base::FilePath default_path;
-        base::PathService::Get(base::DIR_USER_DESKTOP, &default_path);
-        default_path = default_path.Append(FILE_PATH_LITERAL("trace_data.txt"));
-        output_file = default_path.AsUTF8Unsafe().c_str();
-        std::cout << "Saving detailed results to " << output_file << std::endl;
-      }
-
-      if (interactive_) {
-        // Print a summary of the trace.
-        std::cout << BattOrResultsToSummary(results) << endl;
-      }
-
-      std::ofstream trace_stream(output_file);
-      if (!trace_stream.is_open()) {
-        std::cout << "Tracing output file \"" << output_file
-                  << "\" could not be opened." << endl;
-        exit(1);
-      }
-      trace_stream << results.ToString();
-      trace_stream.close();
-      std::cout << "Done." << endl;
-    } else {
-      HandleError(error);
-    }
-
-    if (!interactive_) {
-      ui_thread_message_loop_.task_runner()->PostTask(
-          FROM_HERE, ui_thread_run_loop_.QuitClosure());
-    }
-  }
-
-  void RecordClockSyncMarker(const std::string& marker) {
-    io_thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&BattOrAgent::RecordClockSyncMarker,
-                              base::Unretained(agent_.get()), marker));
-  }
-
-  void OnRecordClockSyncMarkerComplete(BattOrError error) override {
-    if (error == BATTOR_ERROR_NONE)
-      std::cout << "Done." << endl;
-    else
-      HandleError(error);
-
-    PostRunNextCommand();
-  }
-
-  // Postable task for creating the BattOrAgent. Because the BattOrAgent has
-  // uber thread safe dependencies, all interactions with it, including creating
-  // and deleting it, MUST happen on the IO thread.
-  void CreateAgent(
-      const std::string& path,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner,
-      base::WaitableEvent* done) {
-    agent_.reset(new BattOrAgent(path, this, ui_thread_task_runner));
-    done->Signal();
-  }
-
-  // Postable task for deleting the BattOrAgent. See the comment for
-  // CreateAgent() above regarding why this is necessary.
-  void DeleteAgent(base::WaitableEvent* done) {
-    agent_.reset();
-    done->Signal();
-  }
-
- private:
-  // NOTE: ui_thread_message_loop_ must appear before ui_thread_run_loop_ here
-  // because ui_thread_run_loop_ checks for the current MessageLoop during
-  // initialization.
-  base::MessageLoopForUI ui_thread_message_loop_;
-  base::RunLoop ui_thread_run_loop_;
-
-  // Threads needed for serial communication.
-  base::Thread io_thread_;
-
-  // The agent capable of asynchronously communicating with the BattOr.
-  std::unique_ptr<BattOrAgent> agent_;
-
-  std::string trace_output_file_;
-
-  // When true user can Start/Stop tracing by typing Enter.
-  bool interactive_ = false;
-  // Toggle to support alternating starting/stopping tracing.
-  bool is_tracing_ = false;
-};
-
-}  // namespace battor
-
-int main(int argc, char* argv[]) {
-  base::AtExitManager exit_manager;
-  base::CommandLine::Init(argc, argv);
-  battor::BattOrAgentBin bin;
-  base::TaskScheduler::CreateAndStartWithDefaultParams("battor_agent");
-  return bin.Run(argc, argv);
-}
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc
deleted file mode 100644
index d952fc31..0000000
--- a/tools/battor_agent/battor_agent_unittest.cc
+++ /dev/null
@@ -1,1311 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "tools/battor_agent/battor_agent.h"
-
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-using namespace testing;
-
-using std::vector;
-
-namespace battor {
-
-namespace {
-
-BattOrControlMessageAck kInitAck{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0};
-BattOrControlMessageAck kSetGainAck{BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, 0};
-BattOrControlMessageAck kStartTracingAck{
-    BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0};
-const char kClockSyncId[] = "MY_MARKER";
-
-// Creates a byte vector copy of the specified object.
-template <typename T>
-std::unique_ptr<std::vector<char>> ToCharVector(const T& object) {
-  return std::unique_ptr<std::vector<char>>(new std::vector<char>(
-      reinterpret_cast<const char*>(&object),
-      reinterpret_cast<const char*>(&object) + sizeof(T)));
-}
-
-MATCHER_P2(
-    BufferEq,
-    expected_buffer,
-    expected_buffer_size,
-    "Makes sure that the argument has the same contents as the buffer.") {
-  return memcmp(reinterpret_cast<const void*>(arg),
-                reinterpret_cast<const void*>(expected_buffer),
-                expected_buffer_size) == 0;
-}
-
-std::unique_ptr<vector<char>> CreateFrame(const BattOrFrameHeader& frame_header,
-                                          const RawBattOrSample* samples,
-                                          const size_t& num_samples) {
-  std::unique_ptr<vector<char>> bytes(new vector<char>(
-      sizeof(BattOrFrameHeader) + sizeof(RawBattOrSample) * num_samples));
-  memcpy(bytes->data(), &frame_header, sizeof(BattOrFrameHeader));
-  memcpy(bytes->data() + sizeof(BattOrFrameHeader), samples,
-         sizeof(RawBattOrSample) * num_samples);
-
-  return bytes;
-}
-
-class MockBattOrConnection : public BattOrConnection {
- public:
-  MockBattOrConnection(BattOrConnection::Listener* listener)
-      : BattOrConnection(listener) {}
-  ~MockBattOrConnection() override = default;
-
-  MOCK_METHOD0(Open, void());
-  MOCK_METHOD0(Flush, void());
-  MOCK_METHOD0(Close, void());
-  MOCK_METHOD0(IsOpen, bool());
-  MOCK_METHOD3(SendBytes,
-               void(BattOrMessageType type,
-                    const void* buffer,
-                    size_t bytes_to_send));
-  MOCK_METHOD1(ReadMessage, void(BattOrMessageType type));
-  MOCK_METHOD0(CancelReadMessage, void());
-  MOCK_METHOD1(LogSerial, void(const std::string& str));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockBattOrConnection);
-};
-
-}  // namespace
-
-// TestableBattOrAgent uses a fake BattOrConnection to be testable.
-class TestableBattOrAgent : public BattOrAgent {
- public:
-  TestableBattOrAgent(BattOrAgent::Listener* listener,
-                      const base::TickClock* tick_clock)
-      : BattOrAgent("/dev/test", listener, nullptr) {
-    connection_ =
-        std::unique_ptr<BattOrConnection>(new MockBattOrConnection(this));
-    tick_clock_ = tick_clock;
-  }
-
-  MockBattOrConnection* GetConnection() {
-    return static_cast<MockBattOrConnection*>(connection_.get());
-  }
-
-  void OnActionTimeout() override {}
-};
-
-// BattOrAgentTest provides a BattOrAgent and captures the results of its
-// tracing commands.
-class BattOrAgentTest : public testing::Test, public BattOrAgent::Listener {
- public:
-  BattOrAgentTest()
-      : task_runner_(new base::TestMockTimeTaskRunner()),
-        thread_task_runner_handle_(task_runner_) {}
-
-  void OnStartTracingComplete(BattOrError error) override {
-    is_command_complete_ = true;
-    command_error_ = error;
-  }
-
-  void OnStopTracingComplete(const BattOrResults& results,
-                             BattOrError error) override {
-    is_command_complete_ = true;
-    command_error_ = error;
-    trace_ = results.ToString();
-  }
-
-  void OnRecordClockSyncMarkerComplete(BattOrError error) override {
-    is_command_complete_ = true;
-    command_error_ = error;
-  }
-
-  void OnGetFirmwareGitHashComplete(const std::string& firmware_git_hash,
-                                    BattOrError error) override {
-    is_command_complete_ = true;
-    command_error_ = error;
-    firmware_git_hash_ = firmware_git_hash;
-  }
-
-  void OnBytesSent(bool success) {
-    agent_->OnBytesSent(success);
-    task_runner_->RunUntilIdle();
-  }
-
-  void OnMessageRead(bool success,
-                     BattOrMessageType type,
-                     std::unique_ptr<std::vector<char>> bytes) {
-    agent_->OnMessageRead(success, type, std::move(bytes));
-    task_runner_->RunUntilIdle();
-  }
-
-  void OnConnectionFlushed(bool success) {
-    agent_->OnConnectionFlushed(true);
-    task_runner_->RunUntilIdle();
-  }
-
- protected:
-  void SetUp() override {
-    agent_.reset(
-        new TestableBattOrAgent(this, task_runner_->GetMockTickClock()));
-    task_runner_->ClearPendingTasks();
-    is_command_complete_ = false;
-    command_error_ = BATTOR_ERROR_NONE;
-  }
-
-  void AdvanceTickClock(base::TimeDelta delta) {
-    task_runner_->FastForwardBy(delta);
-  }
-
-  // Possible states that the BattOrAgent can be in.
-  enum class BattOrAgentState {
-    // States required to connect to a BattOr.
-    CONNECTED,
-
-    // States required to StartTracing.
-    INIT_SENT,
-    INIT_ACKED,
-    SET_GAIN_SENT,
-    GAIN_ACKED,
-    START_TRACING_SENT,
-    START_TRACING_COMPLETE,
-
-    // States required to StopTracing.
-    EEPROM_REQUEST_SENT,
-    EEPROM_RECEIVED,
-    SAMPLES_REQUEST_SENT,
-    CALIBRATION_FRAME_RECEIVED,
-    SAMPLES_END_FRAME_RECEIVED,
-
-    // States required to RecordClockSyncMarker.
-    CURRENT_SAMPLE_REQUEST_SENT,
-    RECORD_CLOCK_SYNC_MARKER_COMPLETE,
-
-    // States required to GetFirmwareGitHash.
-    GIT_FIRMWARE_HASH_REQUEST_SENT,
-    READ_GIT_HASH_RECEIVED,
-  };
-
-  // Runs BattOrAgent::StartTracing until it reaches the specified state by
-  // feeding it the callbacks it needs to progress.
-  void RunStartTracingTo(BattOrAgentState end_state, bool connect) {
-    GetTaskRunner()->RunUntilIdle();
-
-    if (connect) {
-      GetAgent()->OnConnectionOpened(true);
-      GetTaskRunner()->RunUntilIdle();
-
-      GetAgent()->OnConnectionFlushed(true);
-      GetTaskRunner()->RunUntilIdle();
-    }
-
-    if (end_state == BattOrAgentState::CONNECTED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::INIT_SENT)
-      return;
-
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-    if (end_state == BattOrAgentState::INIT_ACKED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::SET_GAIN_SENT)
-      return;
-
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kSetGainAck));
-    if (end_state == BattOrAgentState::GAIN_ACKED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::START_TRACING_SENT)
-      return;
-
-    // Make sure that we're actually forwarding to a state in the start tracing
-    // state machine.
-    DCHECK(end_state == BattOrAgentState::START_TRACING_COMPLETE);
-
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kStartTracingAck));
-  }
-
-  // Runs BattOrAgent::StopTracing until it reaches the specified state by
-  // feeding it the callbacks it needs to progress.
-  void RunStopTracingTo(BattOrAgentState end_state, bool connect) {
-    GetTaskRunner()->RunUntilIdle();
-
-    if (connect) {
-      GetAgent()->OnConnectionOpened(true);
-      GetTaskRunner()->RunUntilIdle();
-
-      OnConnectionFlushed(true);
-    }
-
-    if (end_state == BattOrAgentState::CONNECTED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::EEPROM_REQUEST_SENT)
-      return;
-
-    BattOrEEPROM eeprom;
-    eeprom.r1 = 1;
-    eeprom.r2 = 1;
-    eeprom.r3 = 1;
-    eeprom.low_gain = 1;
-    eeprom.low_gain_correction_offset = 0;
-    eeprom.low_gain_correction_factor = 1;
-    eeprom.sd_sample_rate = 1000;
-
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(eeprom));
-    if (end_state == BattOrAgentState::EEPROM_RECEIVED)
-      return;
-
-    GetTaskRunner()->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::SAMPLES_REQUEST_SENT)
-      return;
-
-    BattOrFrameHeader cal_frame_header{0, sizeof(RawBattOrSample)};
-    RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                  CreateFrame(cal_frame_header, cal_frame, 1));
-    OnBytesSent(true);
-
-    if (end_state == BattOrAgentState::CALIBRATION_FRAME_RECEIVED)
-      return;
-
-    DCHECK(end_state == BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
-
-    BattOrFrameHeader frame_header{1, 0};
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                  CreateFrame(frame_header, nullptr, 0));
-  }
-
-  // Runs BattOrAgent::RecordClockSyncMarker until it reaches the specified
-  // state by feeding it the callbacks it needs to progress.
-  void RunRecordClockSyncMarkerTo(BattOrAgentState end_state, bool connect) {
-    GetTaskRunner()->RunUntilIdle();
-
-    if (connect) {
-      GetAgent()->OnConnectionOpened(true);
-      GetTaskRunner()->RunUntilIdle();
-
-      OnConnectionFlushed(true);
-    }
-
-    if (end_state == BattOrAgentState::CONNECTED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT)
-      return;
-
-    DCHECK(end_state == BattOrAgentState::RECORD_CLOCK_SYNC_MARKER_COMPLETE);
-
-    uint32_t current_sample = 1;
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(current_sample));
-  }
-
-  // Runs BattOrAgent::GetFirmwareGitHash until it reaches the specified
-  // state by feeding it the callbacks it needs to progress.
-  void RunGetFirmwareGitHashTo(BattOrAgentState end_state, bool connect) {
-    GetTaskRunner()->RunUntilIdle();
-
-    if (connect) {
-      GetAgent()->OnConnectionOpened(true);
-      GetTaskRunner()->RunUntilIdle();
-
-      OnConnectionFlushed(true);
-    }
-
-    if (end_state == BattOrAgentState::CONNECTED)
-      return;
-
-    OnBytesSent(true);
-    if (end_state == BattOrAgentState::GIT_FIRMWARE_HASH_REQUEST_SENT)
-      return;
-
-    DCHECK(end_state == BattOrAgentState::READ_GIT_HASH_RECEIVED);
-
-    std::unique_ptr<std::vector<char>> firmware_git_hash_vector(
-        new std::vector<char>{'G', 'I', 'T', 'H', 'A', 'S', 'H'});
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  std::move(firmware_git_hash_vector));
-  }
-
-  TestableBattOrAgent* GetAgent() { return agent_.get(); }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> GetTaskRunner() {
-    return task_runner_;
-  }
-
-  bool IsCommandComplete() { return is_command_complete_; }
-  BattOrError GetCommandError() { return command_error_; }
-  std::string GetTrace() { return trace_; }
-  std::string GetGitHash() { return firmware_git_hash_; }
-
- private:
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  // Needed to support ThreadTaskRunnerHandle::Get() in code under test.
-  base::ThreadTaskRunnerHandle thread_task_runner_handle_;
-
-  std::unique_ptr<TestableBattOrAgent> agent_;
-  bool is_command_complete_;
-  BattOrError command_error_;
-  std::string trace_;
-  std::string firmware_git_hash_;
-};
-
-TEST_F(BattOrAgentTest, StartTracing) {
-  testing::InSequence s;
-  EXPECT_CALL(*GetAgent()->GetConnection(), Open());
-
-  EXPECT_CALL(*GetAgent()->GetConnection(), Flush());
-
-  BattOrControlMessage init_msg{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0};
-  EXPECT_CALL(
-      *GetAgent()->GetConnection(),
-      SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                BufferEq(&init_msg, sizeof(init_msg)), sizeof(init_msg)));
-
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
-
-  BattOrControlMessage set_gain_msg{BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN,
-                                    BATTOR_GAIN_LOW, 0};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&set_gain_msg, sizeof(set_gain_msg)),
-                        sizeof(set_gain_msg)));
-
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
-
-  BattOrControlMessage start_tracing_msg{
-      BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0, 0};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&start_tracing_msg, sizeof(start_tracing_msg)),
-                        sizeof(start_tracing_msg)));
-
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
-
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsWithoutConnection) {
-  GetAgent()->StartTracing();
-  GetTaskRunner()->RunUntilIdle();
-
-  GetAgent()->OnConnectionOpened(false);
-  GetTaskRunner()->RunUntilIdle();
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsIfInitSendFails) {
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::CONNECTED, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterInitAckReadFails) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterInitWrongAckRead) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kStartTracingAck));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsAfterSetGainSendFails) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSetGainAckReadFails) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT, true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSetGainWrongAckRead) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT, true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kStartTracingAck));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingSendFails) {
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterWrongAckRead) {
-  GetAgent()->StartTracing();
-
-  // Go through the correct init sequence, but give the wrong ack to
-  // START_TRACING.
-  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT, true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterReadFails) {
-  GetAgent()->StartTracing();
-
-  // Go through the correct init sequence, but indicate that we failed to read
-  // the START_TRACING ack.
-  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT, true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // On the last attempt, give the correct ack to START_TRACING.
-  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT, true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kStartTracingAck));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSamplesReadDuringInit) {
-  GetAgent()->StartTracing();
-
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-
-  // Send some samples instead of an INIT ACK. This will force a command retry.
-  BattOrFrameHeader frame_header{1, 3 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2}, RawBattOrSample{3, 3},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, frame, 3));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsAfterTooManyCumulativeFailures) {
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT, true);
-
-  for (int i = 0; i < 9; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-    AdvanceTickClock(base::TimeDelta::FromSeconds(2));
-    RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT, true);
-
-    EXPECT_FALSE(IsCommandComplete());
-  }
-
-  RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT, true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingRestartsConnectionUponRetry) {
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::INIT_SENT, true);
-
-  EXPECT_CALL(*GetAgent()->GetConnection(), Close());
-
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingCanReuseExistingConnection) {
-  ON_CALL(*GetAgent()->GetConnection(), IsOpen()).WillByDefault(Return(true));
-
-  GetAgent()->StartTracing();
-  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE, false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracing) {
-  testing::InSequence s;
-  EXPECT_CALL(*GetAgent()->GetConnection(), Open());
-
-  EXPECT_CALL(*GetAgent()->GetConnection(), Flush());
-
-  BattOrControlMessage request_eeprom_msg{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_EEPROM, sizeof(BattOrEEPROM), 0};
-  EXPECT_CALL(
-      *GetAgent()->GetConnection(),
-      SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                BufferEq(&request_eeprom_msg, sizeof(request_eeprom_msg)),
-                sizeof(request_eeprom_msg)));
-
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
-
-  // The agent sends four frame request messages: one for a calibration frame,
-  // two for data frames with samples, and one for a zero-length data frame to
-  // indicate that we're done.
-  BattOrControlMessage request_samples_msg_frame0{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0, 0};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&request_samples_msg_frame0,
-                                 sizeof(request_samples_msg_frame0)),
-                        sizeof(request_samples_msg_frame0)));
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES));
-
-  BattOrControlMessage request_samples_msg_frame1{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0, 1};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&request_samples_msg_frame1,
-                                 sizeof(request_samples_msg_frame1)),
-                        sizeof(request_samples_msg_frame1)));
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES));
-
-  BattOrControlMessage request_samples_msg_frame2{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0, 2};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&request_samples_msg_frame2,
-                                 sizeof(request_samples_msg_frame2)),
-                        sizeof(request_samples_msg_frame2)));
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES));
-
-  BattOrControlMessage request_samples_msg_frame3{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0, 3};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&request_samples_msg_frame3,
-                                 sizeof(request_samples_msg_frame3)),
-                        sizeof(request_samples_msg_frame3)));
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES));
-
-  GetAgent()->StopTracing();
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  // Send the calibration frame.
-  BattOrFrameHeader cal_frame_header{0, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 2));
-  OnBytesSent(true);
-
-  // Send the two real data frames.
-  BattOrFrameHeader frame_header1{1, 3 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame1[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2}, RawBattOrSample{3, 3},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header1, frame1, 3));
-  OnBytesSent(true);
-
-  BattOrFrameHeader frame_header2{2, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame2[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header2, frame2, 1));
-  OnBytesSent(true);
-
-  // Send an empty last frame to indicate that we're done.
-  BattOrFrameHeader frame_header3{3, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header3, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-  EXPECT_EQ(
-      "# BattOr\n# voltage_range [-2401.8, 2398.2] mV\n# "
-      "current_range [-1200.9, 1199.1] mA\n"
-      "# sample_rate 1000 Hz, gain 1.0x\n"
-      "0.00 -0.3 -0.6\n1.00 0.3 0.6\n2.00 0.9 1.8\n3.00 -0.3 -0.6\n",
-      GetTrace());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsWithoutConnection) {
-  GetAgent()->StopTracing();
-  GetTaskRunner()->RunUntilIdle();
-
-  GetAgent()->OnConnectionOpened(false);
-  GetTaskRunner()->RunUntilIdle();
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsIfEEPROMRequestSendFails) {
-  GetAgent()->StopTracing();
-  RunStopTracingTo(BattOrAgentState::CONNECTED, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterEEPROMReadFails) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT, true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterEEPROMWrongAckRead) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT, true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsIfSendamplesRequestFails) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::EEPROM_RECEIVED, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameReadFailure) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  // Make a read fail in order to make sure that the agent will retry the frame.
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Flush and advance time to send retry for calibration frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  BattOrFrameHeader cal_frame_header{0, sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
-  OnBytesSent(true);
-
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameReadFailure) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  // Make a read fail in order to make sure that the agent will retry.
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsWithManyCalibrationFrameReadFailures) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  for (int i = 0; i < 9; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-    // Flush and advance time to send retry for calibration frame.
-    OnConnectionFlushed(true);
-    AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-    OnBytesSent(true);
-
-    EXPECT_FALSE(IsCommandComplete());
-  }
-
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_FRAME_RETRIES, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsWithManyDataFrameReadFailures) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  for (int i = 0; i < 9; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-    // Flush and advance time to send retry for data frame.
-    OnConnectionFlushed(true);
-    AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-    OnBytesSent(true);
-
-    EXPECT_FALSE(IsCommandComplete());
-  }
-
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_FRAME_RETRIES, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsWithFewDataFrameReadFailures) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  // Fail to receive first data frame.
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Successfully receive the first data frame.
-  BattOrFrameHeader frame_header1{1, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame1[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header1, frame1, 1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Fail to receive next data frame.
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Successfully receive the last data frame.
-  BattOrFrameHeader frame_header2{2, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header2, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterSamplesReadHasWrongType) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  // Send the incorrect type of frame.
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Successfully receive the last data frame.
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameWrongLength) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  // Send a calibration frame with a mismatch between the frame length in the
-  // header and the actual frame length.
-  BattOrFrameHeader cal_frame_header_bad{0, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame_bad[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header_bad, cal_frame_bad, 2));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Flush and advance time to send retry for calibration frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  BattOrFrameHeader cal_frame_header_good{0, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame_good[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header_good, cal_frame_good, 2));
-  OnBytesSent(true);
-
-  // Successfully receive the last data frame.
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameHasWrongLength) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  // Send a data frame with a mismatch between the frame length in the
-  // header and the actual frame length.
-  BattOrFrameHeader frame_header_bad{1, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame_bad[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header_bad, frame_bad, 1));
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Send a data frame with the correct frame length.
-  BattOrFrameHeader frame_header_good{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header_good, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameMissingByte) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  BattOrFrameHeader cal_frame_header_bad{0, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame_bad[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
-  };
-
-  // Remove the last byte from the frame to make it invalid.
-  std::unique_ptr<vector<char>> cal_frame_bad_bytes =
-      CreateFrame(cal_frame_header_bad, cal_frame_bad, 2);
-  cal_frame_bad_bytes->pop_back();
-
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                std::move(cal_frame_bad_bytes));
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Send correct calibration frame and data frame.
-  BattOrFrameHeader cal_frame_header_good{0, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame_good[] = {
-      RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header_good, cal_frame_good, 2));
-  OnBytesSent(true);
-
-  // Successfully receive the last data frame.
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameMissingByte) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  BattOrFrameHeader frame_header_bad{1, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame_bad[] = {RawBattOrSample{1, 1}};
-
-  // Remove the last byte from the frame to make it invalid.
-  std::unique_ptr<vector<char>> frame_bytes_bad =
-      CreateFrame(frame_header_bad, frame_bad, 1);
-  frame_bytes_bad->pop_back();
-
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(frame_bytes_bad));
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Successfully receive the last data frame.
-  BattOrFrameHeader frame_header_good{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header_good, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameArrivesOutOfOrder) {
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED, true);
-
-  // Frame with sequence number 1.
-  BattOrFrameHeader frame_header1{1, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame1[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header1, frame1, 1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Skip frame with sequence number 2.
-  BattOrFrameHeader frame_header3{3, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame3[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header3, frame3, 1));
-
-  // Flush and advance time to send retry for data frame.
-  OnConnectionFlushed(true);
-  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
-  OnBytesSent(true);
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  // Final frame with sequence number 2.
-  BattOrFrameHeader frame_header2{2, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header2, nullptr, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingCanReuseExistingConnection) {
-  ON_CALL(*GetAgent()->GetConnection(), IsOpen()).WillByDefault(Return(true));
-
-  GetAgent()->StopTracing();
-
-  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED, false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarker) {
-  testing::InSequence s;
-  EXPECT_CALL(*GetAgent()->GetConnection(), Open());
-
-  BattOrControlMessage request_current_sample_msg{
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SAMPLE_COUNT, 0, 0};
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                        BufferEq(&request_current_sample_msg,
-                                 sizeof(request_current_sample_msg)),
-                        sizeof(request_current_sample_msg)));
-
-  EXPECT_CALL(*GetAgent()->GetConnection(),
-              ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
-
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-  RunRecordClockSyncMarkerTo(
-      BattOrAgentState::RECORD_CLOCK_SYNC_MARKER_COMPLETE, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerPrintsInStopTracingResult) {
-  // Record a clock sync marker that says CLOCK_SYNC_ID happened at sample #2.
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-
-  RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT,
-                             true);
-
-  uint32_t current_sample = 1;
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(current_sample));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-
-  GetTaskRunner()->FastForwardBy(base::TimeDelta::FromMilliseconds(100));
-  GetAgent()->StopTracing();
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT, true);
-
-  // Now run StopTracing, and make sure that CLOCK_SYNC_ID gets printed out with
-  // sample #2 (including calibration frame samples).
-  BattOrFrameHeader cal_frame_header{0, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
-  OnBytesSent(true);
-
-  BattOrFrameHeader frame_header1{1, 2 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame1[] = {RawBattOrSample{1, 1}, RawBattOrSample{2, 2}};
-
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header1, frame1, 2));
-  OnBytesSent(true);
-
-  BattOrFrameHeader frame_header2{2, 0};
-
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header2, {}, 0));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-  EXPECT_EQ(
-      "# BattOr\n# voltage_range [-2401.2, 2398.8] mV\n# "
-      "current_range [-1200.6, 1199.4] mA\n"
-      "# sample_rate 1000 Hz, gain 1.0x\n"
-      "0.00 0.0 0.0 <MY_MARKER>\n"
-      "1.00 0.6 1.2\n",
-      GetTrace());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerFailsWithoutConnection) {
-  GetAgent()->RecordClockSyncMarker("my_marker");
-  GetTaskRunner()->RunUntilIdle();
-
-  GetAgent()->OnConnectionOpened(false);
-  GetTaskRunner()->RunUntilIdle();
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerFailsIfSampleRequestSendFails) {
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-
-  RunRecordClockSyncMarkerTo(BattOrAgentState::CONNECTED, true);
-  OnBytesSent(false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerFailsIfCurrentSampleReadFails) {
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-
-  RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT,
-                             true);
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest,
-       RecordClockSyncMarkerFailsIfCurrentSampleReadHasWrongType) {
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-
-  RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT,
-                             true);
-
-  uint32_t current_sample = 1;
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL,
-                ToCharVector(current_sample));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerCanReuseExistingConnection) {
-  ON_CALL(*GetAgent()->GetConnection(), IsOpen()).WillByDefault(Return(true));
-
-  GetAgent()->RecordClockSyncMarker(kClockSyncId);
-
-  RunRecordClockSyncMarkerTo(
-      BattOrAgentState::RECORD_CLOCK_SYNC_MARKER_COMPLETE, false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, GetFirmwareGitHash) {
-  GetAgent()->GetFirmwareGitHash();
-
-  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-  EXPECT_EQ("GITHASH", GetGitHash());
-}
-
-TEST_F(BattOrAgentTest, GetFirmwareGitHashFailsWithoutConnection) {
-  GetAgent()->GetFirmwareGitHash();
-
-  GetTaskRunner()->RunUntilIdle();
-
-  GetAgent()->OnConnectionOpened(false);
-  GetTaskRunner()->RunUntilIdle();
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, GetFirmwareGitHashSucceedsReadHasWrongType) {
-  GetAgent()->GetFirmwareGitHash();
-
-  RunGetFirmwareGitHashTo(BattOrAgentState::GIT_FIRMWARE_HASH_REQUEST_SENT,
-                          true);
-
-  uint32_t current_sample = 1;
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL,
-                ToCharVector(current_sample));
-
-  EXPECT_FALSE(IsCommandComplete());
-
-  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, GetFirmwareRestartsConnectionUponRetry) {
-  GetAgent()->GetFirmwareGitHash();
-  RunGetFirmwareGitHashTo(BattOrAgentState::GIT_FIRMWARE_HASH_REQUEST_SENT,
-                          true);
-
-  EXPECT_CALL(*GetAgent()->GetConnection(), Close());
-
-  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-
-  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED, true);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, GetFirmwareGitHashCanReuseExistingConnection) {
-  ON_CALL(*GetAgent()->GetConnection(), IsOpen()).WillByDefault(Return(true));
-
-  GetAgent()->GetFirmwareGitHash();
-
-  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED, false);
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_connection.cc b/tools/battor_agent/battor_connection.cc
deleted file mode 100644
index e6befa1..0000000
--- a/tools/battor_agent/battor_connection.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/battor_agent/battor_connection.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "device/serial/buffer.h"
-#include "device/serial/serial_io_handler.h"
-#include "net/base/io_buffer.h"
-
-namespace battor {
-
-BattOrConnection::BattOrConnection(Listener* listener) : listener_(listener) {}
-BattOrConnection::~BattOrConnection() = default;
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_connection.h b/tools/battor_agent/battor_connection.h
deleted file mode 100644
index 3e4fc54..0000000
--- a/tools/battor_agent/battor_connection.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-namespace battor {
-
-// A BattOrConnection is a wrapper around the serial connection to the BattOr
-// that handles conversion of a message to and from the byte-level BattOr
-// protocol.
-//
-// At a high-level, all BattOr messages consist of:
-//
-//   0x00               (1 byte start marker)
-//   uint8_t            (1 byte header indicating the message type)
-//   data               (message data, with 0x00s and 0x01s escaped with 0x02)
-//   0x01               (1 byte end marker)
-//
-// For a more in-depth description of the protocol, see http://bit.ly/1NvNVc3.
-class BattOrConnection {
- public:
-  // The listener interface that must be implemented in order to interact with
-  // the BattOrConnection.
-  class Listener {
-   public:
-    virtual void OnConnectionOpened(bool success) = 0;
-    virtual void OnConnectionFlushed(bool success) = 0;
-    virtual void OnBytesSent(bool success) = 0;
-    virtual void OnMessageRead(bool success,
-                               BattOrMessageType type,
-                               std::unique_ptr<std::vector<char>> bytes) = 0;
-  };
-
-  BattOrConnection(Listener* listener);
-  virtual ~BattOrConnection() = 0;
-
-  // Opens and initializes the serial connection to the BattOr and calls the
-  // listener's OnConnectionOpened() when complete. As part of this
-  // initialization, the serial connection is flushed by reading and throwing
-  // away bytes until the serial connection remains quiet for a sufficiently
-  // long time. This function must be called before using the
-  // BattOrConnection. If the connection is already open, calling this method
-  // reflushes the connection and then calls the listener's OnConnectionOpened
-  // method.
-  virtual void Open() = 0;
-  // Closes the serial connection and releases any handles being held.
-  virtual void Close() = 0;
-  // Returns true if the connection is currently open.
-  virtual bool IsOpen() = 0;
-  // Flushes the serial connection by reading and throwing away bytes until the
-  // serial connection remains quiet for a sufficiently long time.
-  virtual void Flush() = 0;
-
-  // Sends the specified buffer over the serial connection and calls the
-  // listener's OnBytesSent() when complete. Note that bytes_to_send should not
-  // include the start, end, type, or escape bytes required by the BattOr
-  // protocol.
-  virtual void SendBytes(BattOrMessageType type,
-                         const void* buffer,
-                         size_t bytes_to_send) = 0;
-
-  // Gets the next message available from the serial connection, reading the
-  // correct number of bytes based on the specified message type, and calls the
-  // listener's OnMessageRead() when complete.
-  virtual void ReadMessage(BattOrMessageType type) = 0;
-
-  // Cancels the current message read operation.
-  virtual void CancelReadMessage() = 0;
-
-  // Appends |str| to the serial log file if it exists.
-  virtual void LogSerial(const std::string& str) = 0;
-
- protected:
-  // The listener receiving the results of the commands being executed.
-  Listener* listener_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BattOrConnection);
-};
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_H_
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc
deleted file mode 100644
index 91b9fb8..0000000
--- a/tools/battor_agent/battor_connection_impl.cc
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/battor_agent/battor_connection_impl.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/time/default_tick_clock.h"
-#include "device/serial/buffer.h"
-#include "device/serial/serial_io_handler.h"
-#include "net/base/io_buffer.h"
-#include "tools/battor_agent/serial_utils.h"
-
-using base::StringPrintf;
-using std::vector;
-
-namespace battor {
-
-namespace {
-
-// The command line switch used to specify a file to which serial communication
-// is logged.
-const char kSerialLogPathSwitch[] = "battor-serial-log";
-
-// Serial configuration parameters for the BattOr.
-const uint32_t kBattOrBitrate = 2000000;
-const device::mojom::SerialDataBits kBattOrDataBits =
-    device::mojom::SerialDataBits::EIGHT;
-const device::mojom::SerialParityBit kBattOrParityBit =
-    device::mojom::SerialParityBit::NONE;
-const device::mojom::SerialStopBits kBattOrStopBit =
-    device::mojom::SerialStopBits::ONE;
-const bool kBattOrCtsFlowControl = true;
-const bool kBattOrHasCtsFlowControl = true;
-// The maximum BattOr message is 50kB long.
-const size_t kMaxMessageSizeBytes = 50000;
-// The number of seconds allowed for the connection to open before timing out.
-const uint8_t kConnectTimeoutSeconds = 10;
-const size_t kFlushBufferSize = 50000;
-// The length of time that must pass without receiving any bytes in order for a
-// flush to be considered complete.
-const uint16_t kFlushQuietPeriodThresholdMs = 50;
-
-// Returns the maximum number of bytes that could be required to read a message
-// of the specified type.
-size_t GetMaxBytesForMessageType(BattOrMessageType type) {
-  switch (type) {
-    case BATTOR_MESSAGE_TYPE_CONTROL:
-      return 2 * sizeof(BattOrControlMessage) + 3;
-    case BATTOR_MESSAGE_TYPE_CONTROL_ACK:
-      // The BattOr EEPROM is sent back with this type, even though it's
-      // technically more of a response than an ack. We have to make sure that
-      // we read enough bytes to accommodate this behavior.
-      return 2 * sizeof(BattOrEEPROM) + 3;
-    case BATTOR_MESSAGE_TYPE_SAMPLES:
-      return 2 * kMaxMessageSizeBytes + 3;
-    default:
-      return 0;
-  }
-}
-
-}  // namespace
-
-BattOrConnectionImpl::BattOrConnectionImpl(
-    const std::string& path,
-    BattOrConnection::Listener* listener,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
-    : BattOrConnection(listener),
-      path_(path),
-      is_open_(false),
-      ui_thread_task_runner_(ui_thread_task_runner) {
-  std::string serial_log_path =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          kSerialLogPathSwitch);
-  if (!serial_log_path.empty()) {
-    serial_log_.open(serial_log_path.c_str(),
-                     std::fstream::out | std::fstream::trunc);
-  }
-  tick_clock_ = base::DefaultTickClock::GetInstance();
-}
-
-BattOrConnectionImpl::~BattOrConnectionImpl() = default;
-
-void BattOrConnectionImpl::Open() {
-  if (io_handler_) {
-    LogSerial("Serial connection already open.");
-
-    // Skip flushing the connection because it's already open.
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
-                              base::Unretained(listener_), true));
-    return;
-  }
-
-  io_handler_ = CreateIoHandler();
-
-  device::mojom::SerialConnectionOptions options;
-  options.bitrate = kBattOrBitrate;
-  options.data_bits = kBattOrDataBits;
-  options.parity_bit = kBattOrParityBit;
-  options.stop_bits = kBattOrStopBit;
-  options.cts_flow_control = kBattOrCtsFlowControl;
-  options.has_cts_flow_control = kBattOrHasCtsFlowControl;
-
-  LogSerial("Opening serial connection.");
-  SetTimeout(base::TimeDelta::FromSeconds(kConnectTimeoutSeconds));
-  io_handler_->Open(
-      path_, options,
-      base::BindOnce(&BattOrConnectionImpl::OnOpened, AsWeakPtr()));
-}
-
-void BattOrConnectionImpl::OnOpened(bool success) {
-  LogSerial(StringPrintf("Serial connection open finished with success: %d.",
-                         success));
-  timeout_callback_.Cancel();
-
-  if (!success) {
-    Close();
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
-                              base::Unretained(listener_), false));
-    return;
-  }
-
-  is_open_ = true;
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
-                            base::Unretained(listener_), true));
-}
-
-void BattOrConnectionImpl::Close() {
-  LogSerial("Serial connection closed.");
-  io_handler_ = nullptr;
-  is_open_ = false;
-}
-
-bool BattOrConnectionImpl::IsOpen() {
-  return is_open_;
-}
-
-void BattOrConnectionImpl::SendBytes(BattOrMessageType type,
-                                     const void* buffer,
-                                     size_t bytes_to_send) {
-  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
-
-  // Reserve a send buffer with enough extra bytes for the start, type, end, and
-  // escape bytes.
-  vector<uint8_t> data;
-  data.reserve(2 * bytes_to_send + 3);
-
-  data.push_back(BATTOR_CONTROL_BYTE_START);
-  data.push_back(type);
-
-  for (size_t i = 0; i < bytes_to_send; i++) {
-    if (bytes[i] == BATTOR_CONTROL_BYTE_START ||
-        bytes[i] == BATTOR_CONTROL_BYTE_END ||
-        bytes[i] == BATTOR_CONTROL_BYTE_ESCAPE)
-      data.push_back(BATTOR_CONTROL_BYTE_ESCAPE);
-
-    data.push_back(bytes[i]);
-  }
-
-  data.push_back(BATTOR_CONTROL_BYTE_END);
-
-  LogSerial(StringPrintf("Bytes sent: %s.", ByteVectorToString(data).c_str()));
-
-  pending_write_length_ = data.size();
-  io_handler_->Write(std::make_unique<device::SendBuffer>(
-      data, base::BindOnce(&BattOrConnectionImpl::OnBytesSent, AsWeakPtr())));
-}
-
-void BattOrConnectionImpl::ReadMessage(BattOrMessageType type) {
-  LogSerial("Read requested.");
-
-  pending_read_message_type_ = type;
-  size_t message_max_bytes = GetMaxBytesForMessageType(type);
-
-  LogSerial(
-      "Before doing a serial read, checking to see if we already have a "
-      "complete message in the 'already read' buffer.");
-
-  BattOrMessageType parsed_type;
-  std::unique_ptr<vector<char>> bytes(new vector<char>());
-  bytes->reserve(message_max_bytes);
-  ParseMessageError parse_message_error =
-      ParseMessage(&parsed_type, bytes.get());
-  if (parse_message_error == ParseMessageError::NONE) {
-    LogSerial("Complete message found.");
-    EndReadBytesForMessage(true, parsed_type, std::move(bytes));
-    return;
-  }
-
-  if (parse_message_error != ParseMessageError::NOT_ENOUGH_BYTES) {
-    LogSerial(StringPrintf(
-        "Read failed because, before performing a serial read, the message in "
-        "the 'already read' buffer had an irrecoverable error with code: %d.",
-        parse_message_error));
-    EndReadBytesForMessage(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
-    return;
-  }
-
-  LogSerial("No complete message found in the 'already read' buffer.");
-  BeginReadBytesForMessage(message_max_bytes - already_read_buffer_.size());
-}
-
-void BattOrConnectionImpl::CancelReadMessage() {
-  LogSerial("Canceling read due to timeout.");
-  io_handler_->CancelRead(device::mojom::SerialReceiveError::TIMEOUT);
-}
-
-scoped_refptr<device::SerialIoHandler> BattOrConnectionImpl::CreateIoHandler() {
-  return device::SerialIoHandler::Create(ui_thread_task_runner_);
-}
-
-void BattOrConnectionImpl::BeginReadBytesForMessage(size_t max_bytes_to_read) {
-  LogSerial(StringPrintf("(message) Starting read of up to %zu bytes.",
-                         max_bytes_to_read));
-
-  pending_read_buffer_ = base::MakeRefCounted<net::IOBuffer>(max_bytes_to_read);
-
-  io_handler_->Read(std::make_unique<device::ReceiveBuffer>(
-      pending_read_buffer_, static_cast<uint32_t>(max_bytes_to_read),
-      base::BindOnce(&BattOrConnectionImpl::OnBytesReadForMessage,
-                     AsWeakPtr())));
-}
-
-void BattOrConnectionImpl::OnBytesReadForMessage(
-    int bytes_read,
-    device::mojom::SerialReceiveError error) {
-  if (error != device::mojom::SerialReceiveError::NONE) {
-    LogSerial(StringPrintf(
-        "(message) Read failed due to serial read failure with error code: %d.",
-        static_cast<int>(error)));
-    EndReadBytesForMessage(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
-    return;
-  }
-
-  // NOTE: Zero bytes may have been read.
-
-  if (pending_read_message_type_ == BATTOR_MESSAGE_TYPE_SAMPLES) {
-    // If we're reading samples, don't log every byte that we receive. This
-    // exacerbates a problem on Mac wherein we can't process sample frames
-    // quickly enough to prevent the serial buffer from overflowing, causing us
-    // to drop frames.
-    LogSerial(StringPrintf("(message) %d more bytes read.", bytes_read));
-  } else {
-    LogSerial(StringPrintf(
-        "(message) %d more bytes read: %s.", bytes_read,
-        CharArrayToString(pending_read_buffer_->data(), bytes_read).c_str()));
-  }
-
-  already_read_buffer_.insert(already_read_buffer_.end(),
-                              pending_read_buffer_->data(),
-                              pending_read_buffer_->data() + bytes_read);
-
-  BattOrMessageType type;
-  size_t message_max_bytes =
-      GetMaxBytesForMessageType(pending_read_message_type_);
-  std::unique_ptr<vector<char>> bytes(new vector<char>());
-  bytes->reserve(message_max_bytes);
-
-  ParseMessageError parse_message_error = ParseMessage(&type, bytes.get());
-  if (parse_message_error == ParseMessageError::NOT_ENOUGH_BYTES) {
-    if (already_read_buffer_.size() >= message_max_bytes) {
-      LogSerial(
-          "(message) Read failed due to no complete message after max read "
-          "length.");
-      EndReadBytesForMessage(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
-      return;
-    }
-
-    LogSerial("(message) Still incomplete: reading more bytes.)");
-    BeginReadBytesForMessage(message_max_bytes - already_read_buffer_.size());
-    return;
-  }
-
-  if (parse_message_error != ParseMessageError::NONE) {
-    LogSerial(
-        StringPrintf("(message) Read failed due to the message containing an "
-                     "irrecoverable error: %d.",
-                     parse_message_error));
-    EndReadBytesForMessage(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
-    return;
-  }
-
-  if (type != pending_read_message_type_) {
-    LogSerial(
-        "(message) Read failed due to receiving a message of the wrong type.");
-    EndReadBytesForMessage(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
-    return;
-  }
-
-  EndReadBytesForMessage(true, type, std::move(bytes));
-}
-
-void BattOrConnectionImpl::EndReadBytesForMessage(
-    bool success,
-    BattOrMessageType type,
-    std::unique_ptr<vector<char>> bytes) {
-  LogSerial(StringPrintf("(message) Read finished with success: %d.", success));
-
-  pending_read_buffer_ = nullptr;
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&Listener::OnMessageRead, base::Unretained(listener_), success,
-                 type, base::Passed(std::move(bytes))));
-}
-
-void BattOrConnectionImpl::Flush() {
-  already_read_buffer_.clear();
-  flush_quiet_period_start_ = tick_clock_->NowTicks();
-  BeginReadBytesForFlush();
-}
-
-void BattOrConnectionImpl::BeginReadBytesForFlush() {
-  base::TimeDelta quiet_period_duration =
-      tick_clock_->NowTicks() - flush_quiet_period_start_;
-  LogSerial(
-      StringPrintf("(flush) Starting read (quiet period has lasted %f ms).",
-                   quiet_period_duration.InMillisecondsF()));
-
-  pending_read_buffer_ = base::MakeRefCounted<net::IOBuffer>(kFlushBufferSize);
-
-  io_handler_->Read(std::make_unique<device::ReceiveBuffer>(
-      pending_read_buffer_, static_cast<uint32_t>(kFlushBufferSize),
-      base::BindOnce(&BattOrConnectionImpl::OnBytesReadForFlush,
-                     base::Unretained(this))));
-  SetTimeout(base::TimeDelta::FromMilliseconds(kFlushQuietPeriodThresholdMs));
-}
-
-void BattOrConnectionImpl::SetTimeout(base::TimeDelta timeout) {
-  timeout_callback_.Reset(
-      base::Bind(&BattOrConnectionImpl::CancelReadMessage, AsWeakPtr()));
-  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, timeout_callback_.callback(), timeout);
-}
-
-void BattOrConnectionImpl::OnBytesReadForFlush(
-    int bytes_read,
-    device::mojom::SerialReceiveError error) {
-  timeout_callback_.Cancel();
-
-  if (error != device::mojom::SerialReceiveError::NONE &&
-      error != device::mojom::SerialReceiveError::TIMEOUT) {
-    LogSerial(StringPrintf(
-        "(flush) Read failed due to serial read failure with error code: %d.",
-        static_cast<int>(error)));
-    pending_read_buffer_ = nullptr;
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&Listener::OnConnectionFlushed,
-                              base::Unretained(listener_), false));
-    return;
-  }
-
-  LogSerial(StringPrintf("(flush) %i additional bytes read.", bytes_read));
-  if (bytes_read == 0 || error == device::mojom::SerialReceiveError::TIMEOUT) {
-    // Reading zero bytes or a serial read timeout both indicate that the
-    // connection was quiet.
-    base::TimeDelta quiet_period_duration =
-        tick_clock_->NowTicks() - flush_quiet_period_start_;
-    if (quiet_period_duration >=
-        base::TimeDelta::FromMilliseconds(kFlushQuietPeriodThresholdMs)) {
-      LogSerial("(flush) Quiet period has finished.");
-      pending_read_buffer_ = nullptr;
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&Listener::OnConnectionFlushed,
-                                base::Unretained(listener_), true));
-      return;
-    }
-
-    // If we didn't receive bytes but the quiet period hasn't elapsed, try to
-    // read again after a delay.
-    LogSerial(StringPrintf("(flush) Reading more bytes after %u ms delay.",
-                           kFlushQuietPeriodThresholdMs));
-    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&BattOrConnectionImpl::BeginReadBytesForFlush,
-                       AsWeakPtr()),
-        base::TimeDelta::FromMilliseconds(kFlushQuietPeriodThresholdMs));
-    return;
-  }
-
-  // We received additional bytes: restart the quiet period and read more bytes.
-  flush_quiet_period_start_ = tick_clock_->NowTicks();
-  BeginReadBytesForFlush();
-}
-
-BattOrConnectionImpl::ParseMessageError BattOrConnectionImpl::ParseMessage(
-    BattOrMessageType* type,
-    vector<char>* bytes) {
-  if (already_read_buffer_.size() <= 3)
-    return ParseMessageError::NOT_ENOUGH_BYTES;
-
-  // The first byte is the start byte.
-  if (already_read_buffer_[0] != BATTOR_CONTROL_BYTE_START)
-    return ParseMessageError::MISSING_START_BYTE;
-
-  // The second byte specifies the message type.
-  *type = static_cast<BattOrMessageType>(already_read_buffer_[1]);
-
-  if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) ||
-      *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT))
-    return ParseMessageError::INVALID_MESSAGE_TYPE;
-
-  // After that comes the message bytes.
-  bool escape_next_byte = false;
-  for (size_t i = 2; i < already_read_buffer_.size(); i++) {
-    char next_byte = already_read_buffer_[i];
-
-    if (escape_next_byte) {
-      bytes->push_back(next_byte);
-      escape_next_byte = false;
-      continue;
-    }
-
-    switch (next_byte) {
-      case BATTOR_CONTROL_BYTE_START:
-        // Two start bytes in a message is invalid.
-        return ParseMessageError::TOO_MANY_START_BYTES;
-
-      case BATTOR_CONTROL_BYTE_END:
-        already_read_buffer_.erase(already_read_buffer_.begin(),
-                                   already_read_buffer_.begin() + i + 1);
-        return ParseMessageError::NONE;
-
-      case BATTOR_CONTROL_BYTE_ESCAPE:
-        escape_next_byte = true;
-        continue;
-
-      default:
-        bytes->push_back(next_byte);
-    }
-  }
-
-  // If we made it to the end of the read buffer and no end byte was seen, then
-  // we don't have a complete message.
-  return ParseMessageError::NOT_ENOUGH_BYTES;
-}
-
-void BattOrConnectionImpl::OnBytesSent(int bytes_sent,
-                                       device::mojom::SerialSendError error) {
-  bool success = (error == device::mojom::SerialSendError::NONE) &&
-                 (pending_write_length_ == static_cast<size_t>(bytes_sent));
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&Listener::OnBytesSent, base::Unretained(listener_), success));
-}
-
-void BattOrConnectionImpl::LogSerial(const std::string& str) {
-  serial_log_ << base::Time::Now() << ": " << str << std::endl << std::endl;
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_connection_impl.h b/tools/battor_agent/battor_connection_impl.h
deleted file mode 100644
index ee2cc39..0000000
--- a/tools/battor_agent/battor_connection_impl.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_IMPL_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_IMPL_H_
-
-#include <fstream>
-#include <memory>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/tick_clock.h"
-#include "services/device/public/mojom/serial.mojom.h"
-#include "tools/battor_agent/battor_connection.h"
-#include "tools/battor_agent/battor_error.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-namespace device {
-class SerialIoHandler;
-}
-namespace net {
-class IOBuffer;
-}
-
-namespace battor {
-
-// A BattOrConnectionImpl is a concrete implementation of a BattOrConnection.
-class BattOrConnectionImpl
-    : public BattOrConnection,
-      public base::SupportsWeakPtr<BattOrConnectionImpl> {
- public:
-  BattOrConnectionImpl(
-      const std::string& path,
-      BattOrConnection::Listener* listener,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
-  ~BattOrConnectionImpl() override;
-
-  void Open() override;
-  void Close() override;
-  bool IsOpen() override;
-  void SendBytes(BattOrMessageType type,
-                 const void* buffer,
-                 size_t bytes_to_send) override;
-  void ReadMessage(BattOrMessageType type) override;
-  void CancelReadMessage() override;
-  void LogSerial(const std::string& str) override;
-
-  // Flushes the serial connection to the BattOr, reading and throwing away
-  // bytes from the serial connection until the connection is quiet for a
-  // sufficiently long time. This also discards any trailing bytes from past
-  // successful reads.
-  void Flush() override;
-
- protected:
-  // Overridden by the test to use a fake serial connection.
-  virtual scoped_refptr<device::SerialIoHandler> CreateIoHandler();
-
-  // IO handler capable of reading and writing from the serial connection.
-  scoped_refptr<device::SerialIoHandler> io_handler_;
-
-  const base::TickClock* tick_clock_;
-
- private:
-  void OnOpened(bool success);
-
-  // Reads the specified number of additional bytes and adds them to the pending
-  // read buffer.
-  void BeginReadBytesForMessage(size_t bytes_to_read);
-
-  // Internal callback for when bytes are read. This method may trigger
-  // additional reads if any newly read bytes are escape bytes.
-  void OnBytesReadForMessage(int bytes_read,
-                             device::mojom::SerialReceiveError error);
-
-  void EndReadBytesForMessage(bool success,
-                              BattOrMessageType type,
-                              std::unique_ptr<std::vector<char>> data);
-
-  void BeginReadBytesForFlush();
-  void OnBytesReadForFlush(int bytes_read,
-                           device::mojom::SerialReceiveError error);
-  void SetTimeout(base::TimeDelta timeout);
-
-  // Pulls off the next complete message from already_read_buffer_, returning
-  // its type and contents through out parameters and any error that occurred
-  // through the return value.
-  enum ParseMessageError {
-    NONE = 0,
-    NOT_ENOUGH_BYTES = 1,
-    MISSING_START_BYTE = 2,
-    INVALID_MESSAGE_TYPE = 3,
-    TOO_MANY_START_BYTES = 4
-  };
-
-  ParseMessageError ParseMessage(BattOrMessageType* type,
-                                 std::vector<char>* data);
-
-  // Internal callback for when bytes are sent.
-  void OnBytesSent(int bytes_sent, device::mojom::SerialSendError error);
-
-  // The path of the BattOr.
-  std::string path_;
-
-  // Indicates whether the connection is currently open.
-  bool is_open_;
-
-  // All bytes that have already been read from the serial stream, but have not
-  // yet been given to the listener as a complete message.
-  std::vector<char> already_read_buffer_;
-  // The bytes that were read in the pending read.
-  scoped_refptr<net::IOBuffer> pending_read_buffer_;
-  // The type of message we're looking for in the pending read.
-  BattOrMessageType pending_read_message_type_;
-
-  // The total number of bytes that we're expecting to send.
-  size_t pending_write_length_;
-
-  // The start of the period over which no bytes must be read from the serial
-  // connection in order for Flush() to be considered complete.
-  base::TimeTicks flush_quiet_period_start_;
-
-  // The timeout for the current action.
-  base::CancelableClosure timeout_callback_;
-
-  // Threads needed for serial communication.
-  scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
-
-  std::fstream serial_log_;
-
-  DISALLOW_COPY_AND_ASSIGN(BattOrConnectionImpl);
-};
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_CONNECTION_IMPL_H_
diff --git a/tools/battor_agent/battor_connection_impl_unittest.cc b/tools/battor_agent/battor_connection_impl_unittest.cc
deleted file mode 100644
index eddce4d..0000000
--- a/tools/battor_agent/battor_connection_impl_unittest.cc
+++ /dev/null
@@ -1,731 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/battor_agent/battor_connection_impl.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/weak_ptr.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "device/serial/test_serial_io_handler.h"
-#include "services/device/public/mojom/serial.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-namespace {
-
-void NullWriteCallback(int, device::mojom::SerialSendError) {}
-void NullReadCallback(int, device::mojom::SerialReceiveError) {}
-
-}  // namespace
-
-namespace battor {
-
-// TestableBattOrConnection uses a fake serial connection be testable.
-class TestableBattOrConnection : public BattOrConnectionImpl {
- public:
-  TestableBattOrConnection(BattOrConnection::Listener* listener,
-                           const base::TickClock* tick_clock)
-      : BattOrConnectionImpl("/dev/test", listener, nullptr) {
-    tick_clock_ = tick_clock;
-  }
-  scoped_refptr<device::SerialIoHandler> CreateIoHandler() override {
-    return device::TestSerialIoHandler::Create();
-  }
-
-  device::TestSerialIoHandler* GetIoHandler() {
-    return reinterpret_cast<device::TestSerialIoHandler*>(io_handler_.get());
-  }
-};
-
-// BattOrConnectionImplTest provides a BattOrConnection and captures the
-// results of all its commands.
-class BattOrConnectionImplTest : public testing::Test,
-                                 public BattOrConnection::Listener {
- public:
-  BattOrConnectionImplTest()
-      : task_runner_(new base::TestMockTimeTaskRunner()),
-        thread_task_runner_handle_(task_runner_) {}
-
-  void OnConnectionOpened(bool success) override {
-    is_open_complete_ = true;
-    open_success_ = success;
-  };
-  void OnConnectionFlushed(bool success) override {
-    is_flush_complete_ = true;
-    flush_success_ = success;
-  };
-  void OnBytesSent(bool success) override { send_success_ = success; }
-  void OnMessageRead(bool success,
-                     BattOrMessageType type,
-                     std::unique_ptr<std::vector<char>> bytes) override {
-    is_read_complete_ = true;
-    read_success_ = success;
-    read_type_ = type;
-    read_bytes_ = std::move(bytes);
-  }
-
- protected:
-  void SetUp() override {
-    connection_.reset(
-        new TestableBattOrConnection(this, task_runner_->GetMockTickClock()));
-    task_runner_->ClearPendingTasks();
-  }
-
-  void OpenConnection() {
-    is_open_complete_ = false;
-    connection_->Open();
-    task_runner_->RunUntilIdle();
-  }
-
-  void FlushConnection() {
-    is_flush_complete_ = false;
-    connection_->Flush();
-    task_runner_->RunUntilIdle();
-  }
-
-  bool IsConnectionOpen() { return connection_->IsOpen(); }
-
-  void CloseConnection() { connection_->Close(); }
-
-  void ReadMessage(BattOrMessageType type) {
-    is_read_complete_ = false;
-    connection_->ReadMessage(type);
-    task_runner_->RunUntilIdle();
-  }
-
-  // Reads the specified number of bytes directly from the serial connection.
-  scoped_refptr<net::IOBuffer> ReadMessageRaw(int bytes_to_read) {
-    scoped_refptr<net::IOBuffer> buffer(
-        new net::IOBuffer((size_t)bytes_to_read));
-
-    connection_->GetIoHandler()->Read(std::make_unique<device::ReceiveBuffer>(
-        buffer, bytes_to_read, base::BindOnce(&NullReadCallback)));
-    task_runner_->RunUntilIdle();
-
-    return buffer;
-  }
-
-  void SendControlMessage(BattOrControlMessageType type,
-                          uint16_t param1,
-                          uint16_t param2) {
-    BattOrControlMessage msg{type, param1, param2};
-    connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL,
-                           reinterpret_cast<char*>(&msg), sizeof(msg));
-    task_runner_->RunUntilIdle();
-  }
-
-  void ForceReceiveError(device::mojom::SerialReceiveError error) {
-    connection_->GetIoHandler()->ForceReceiveError(error);
-    task_runner_->RunUntilIdle();
-  }
-
-  // Writes the specified bytes directly to the serial connection.
-  void SendBytesRaw(const char* data, uint16_t bytes_to_send) {
-    connection_->GetIoHandler()->Write(std::make_unique<device::SendBuffer>(
-        std::vector<uint8_t>(data, data + bytes_to_send),
-        base::BindOnce(&NullWriteCallback)));
-    task_runner_->RunUntilIdle();
-  }
-
-  void AdvanceTickClock(base::TimeDelta delta) {
-    task_runner_->FastForwardBy(delta);
-  }
-
-  bool GetOpenSuccess() { return open_success_; }
-  bool GetFlushSuccess() { return flush_success_; }
-  bool IsOpenComplete() { return is_open_complete_; }
-  bool IsFlushComplete() { return is_flush_complete_; }
-  bool GetSendSuccess() { return send_success_; }
-  bool IsReadComplete() { return is_read_complete_; }
-  bool GetReadSuccess() { return read_success_; }
-  BattOrMessageType GetReadType() { return read_type_; }
-  std::vector<char>* GetReadMessage() { return read_bytes_.get(); }
-
- private:
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle thread_task_runner_handle_;
-
-  std::unique_ptr<TestableBattOrConnection> connection_;
-
-  // Result from the last connect command.
-  bool open_success_;
-  // Results from the last flush command.
-  bool flush_success_;
-  bool is_open_complete_;
-  bool is_flush_complete_;
-  // Result from the last send command.
-  bool send_success_;
-  // Results from the last read command.
-  bool is_read_complete_;
-  bool read_success_;
-  BattOrMessageType read_type_;
-  std::unique_ptr<std::vector<char>> read_bytes_;
-};
-
-TEST_F(BattOrConnectionImplTest, OpenConnectionSucceedsImmediately) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-  ASSERT_TRUE(IsConnectionOpen());
-}
-
-TEST_F(BattOrConnectionImplTest, IsOpenFalseAfterClosingConnection) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-  ASSERT_TRUE(IsConnectionOpen());
-
-  CloseConnection();
-
-  ASSERT_FALSE(IsConnectionOpen());
-}
-
-TEST_F(BattOrConnectionImplTest, FlushConnectionSucceedsOnlyAfterTimeout) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  ASSERT_FALSE(IsFlushComplete());
-
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  ASSERT_TRUE(IsFlushComplete());
-  ASSERT_TRUE(GetFlushSuccess());
-}
-
-#if defined(ADDRESS_SANITIZER)
-// https://crbug.com/843729
-#define MAYBE_FlushConnectionFlushesAlreadyReadBuffer \
-  DISABLED_FlushConnectionFlushesAlreadyReadBuffer
-#else
-#define MAYBE_FlushConnectionFlushesAlreadyReadBuffer \
-  FlushConnectionFlushesAlreadyReadBuffer
-#endif
-TEST_F(BattOrConnectionImplTest,
-       MAYBE_FlushConnectionFlushesAlreadyReadBuffer) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  // Send two data frames and only read one of them. When reading data frames,
-  // we try to read a large chunk from the wire due to the large potential size
-  // of a data frame (~100kB). By sending two tiny data frames on the wire and
-  // reading back one of them, we know that we read past the end of the first
-  // message and all of the second message because the data frames were so
-  // small. These extra bytes that were unnecesssary for the first message were
-  // storied internally by BattOrConnectionImpl, and we want to ensure that
-  // Flush() clears this internal data.
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_SAMPLES,
-      0x02,
-      0x00,
-      0x02,
-      0x00,
-      0x02,
-      0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 9);
-  SendBytesRaw(data, 9);
-  ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES);
-
-  CloseConnection();
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES);
-
-  // The read should be incomplete due to no data being on the wire - the second
-  // control message was cleared by the slow flush.
-  ASSERT_FALSE(IsReadComplete());
-}
-
-TEST_F(BattOrConnectionImplTest, FlushConnectionNewBytesRestartQuietPeriod) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(49));
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7);
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(49));
-
-  // The connection should not yet be opened because we received new bytes at
-  // t=49ms, and at t=98ms the new 50ms quiet period hasn't yet elapsed.
-  ASSERT_FALSE(IsFlushComplete());
-
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(1));
-
-  ASSERT_TRUE(IsFlushComplete());
-}
-
-#if defined(ADDRESS_SANITIZER)
-// https://crbug.com/843729
-#define MAYBE_FlushConnectionFlushesBytesReceivedInQuietPeriod \
-  DISABLED_FlushConnectionFlushesBytesReceivedInQuietPeriod
-#else
-#define MAYBE_FlushConnectionFlushesBytesReceivedInQuietPeriod \
-  FlushConnectionFlushesBytesReceivedInQuietPeriod
-#endif
-TEST_F(BattOrConnectionImplTest,
-       MAYBE_FlushConnectionFlushesBytesReceivedInQuietPeriod) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7);
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(5));
-  ASSERT_FALSE(IsFlushComplete());
-
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7);
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-  ASSERT_TRUE(IsFlushComplete());
-  ASSERT_TRUE(GetFlushSuccess());
-
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  // The read should hang because the control message that arrived mid quiet
-  // period was thrown out.
-  ASSERT_FALSE(IsReadComplete());
-}
-
-TEST_F(BattOrConnectionImplTest, FlushConnectionFlushesMultipleReadsOfData) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  // Send 10 full flush buffers worth of data.
-  char data[50000];
-  for (size_t i = 0; i < 50000; i++)
-    data[i] = '0';
-  for (int i = 0; i < 10; i++)
-    SendBytesRaw(data, 50000);
-
-  FlushConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  // Even though 500kB of garbage data was sent before the valid control
-  // message on the serial connection, the slow flush should have cleared it
-  // all, resulting in a successful read.
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-}
-
-#if defined(ADDRESS_SANITIZER)
-// https://crbug.com/843729
-#define MAYBE_FlushIncompleteBeforeTimeout DISABLED_FlushIncompleteBeforeTimeout
-#else
-#define MAYBE_FlushIncompleteBeforeTimeout FlushIncompleteBeforeTimeout
-#endif
-TEST_F(BattOrConnectionImplTest, MAYBE_FlushIncompleteBeforeTimeout) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(49));
-
-  ASSERT_FALSE(IsFlushComplete());
-}
-
-TEST_F(BattOrConnectionImplTest, FlushFailsWithNonTimeoutError) {
-  OpenConnection();
-  ASSERT_TRUE(IsOpenComplete());
-  ASSERT_TRUE(GetOpenSuccess());
-
-  FlushConnection();
-  ForceReceiveError(device::mojom::SerialReceiveError::DISCONNECTED);
-
-  ASSERT_FALSE(GetFlushSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ControlSendEscapesStartBytesCorrectly) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(
-      BATTOR_CONTROL_MESSAGE_TYPE_INIT,
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_CONTROL_BYTE_START);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_INIT,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_START,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_START,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13));
-}
-
-TEST_F(BattOrConnectionImplTest, ControlSendEscapesEndBytesCorrectly) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      BATTOR_CONTROL_BYTE_END,
-      BATTOR_CONTROL_BYTE_END);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_END,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_END,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13));
-}
-
-TEST_F(BattOrConnectionImplTest, ControlSendEscapesEscapeBytesCorrectly) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(
-      BATTOR_CONTROL_MESSAGE_TYPE_SELF_TEST,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_BYTE_ESCAPE);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_SELF_TEST,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13));
-}
-
-TEST_F(BattOrConnectionImplTest, ControlSendEscapesParametersCorrectly) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  // Check if the two control parameters are ordered and escaped properly.
-  // This also checks the byte ordering of the two 16-bit control message
-  // parameters, which should be little-endian on the wire.
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0x0100, 0x0002);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x01,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x02,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(12)->data(), expected_data, 12));
-}
-
-TEST_F(BattOrConnectionImplTest, InitSendsCorrectBytes) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START,  BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_INIT,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13));
-}
-
-TEST_F(BattOrConnectionImplTest, ResetSendsCorrectBytes) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0, 0);
-
-  const char expected_data[] = {
-      BATTOR_CONTROL_BYTE_START,  BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_ESCAPE, 0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-
-  ASSERT_TRUE(GetSendSuccess());
-  ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13));
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageControlMessage) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      0x04,
-      0x04,
-      0x04,
-      0x04,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 9);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  const char expected[] = {BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0x04, 0x04, 0x04,
-                           0x04};
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-  ASSERT_EQ(BATTOR_MESSAGE_TYPE_CONTROL, GetReadType());
-  ASSERT_EQ(0, std::memcmp(GetReadMessage()->data(), expected, 5));
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageInvalidType) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      static_cast<char>(UINT8_MAX),
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      0x04,
-      0x04,
-      0x04,
-      0x04,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 7);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageEndsMidMessage) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      0x04,
-  };
-  SendBytesRaw(data, 5);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  // The first read should recognize that a second read is necessary.
-  ASSERT_FALSE(IsReadComplete());
-
-  ForceReceiveError(device::mojom::SerialReceiveError::TIMEOUT);
-
-  // The second read should fail due to the time out.
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageMissingEndByte) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      0x04,
-      0x04,
-      0x04,
-      0x04,
-  };
-  SendBytesRaw(data, 6);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  // The first read should recognize that a second read is necessary.
-  ASSERT_FALSE(IsReadComplete());
-
-  ForceReceiveError(device::mojom::SerialReceiveError::TIMEOUT);
-
-  // The second read should fail due to the time out.
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageWithEscapeCharacters) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_CONTROL,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      0x00,
-      0x04,
-      0x04,
-      0x04,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 10);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  const char expected[] = {BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0x00};
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-  ASSERT_EQ(BATTOR_MESSAGE_TYPE_CONTROL, GetReadType());
-  ASSERT_EQ(0, std::memcmp(GetReadMessage()->data(), expected, 2));
-}
-
-TEST_F(BattOrConnectionImplTest, ReadControlMessage) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-  ASSERT_EQ(BATTOR_MESSAGE_TYPE_CONTROL, GetReadType());
-
-  BattOrControlMessage* msg =
-      reinterpret_cast<BattOrControlMessage*>(GetReadMessage()->data());
-
-  ASSERT_EQ(BATTOR_CONTROL_MESSAGE_TYPE_RESET, msg->type);
-  ASSERT_EQ(4, msg->param1);
-  ASSERT_EQ(7, msg->param2);
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageExtraBytesStoredBetweenReads) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  // Send a samples frame with length and sequence number of zero.
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_SAMPLES,
-      0x02,
-      0x00,
-      0x02,
-      0x00,
-      0x02,
-      0x00,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 9);
-  SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 5, 8);
-
-  // When reading sample frames, we're forced to read lots because each frame
-  // could be up to 50kB long. By reading a really short sample frame (like
-  // the zero-length one above), the BattOrConnection is forced to store
-  // whatever extra data it finds in the serial stream - in this case, the
-  // init control message that we sent.
-  ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-  ASSERT_EQ(BATTOR_MESSAGE_TYPE_SAMPLES, GetReadType());
-
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_TRUE(GetReadSuccess());
-  ASSERT_EQ(BATTOR_MESSAGE_TYPE_CONTROL, GetReadType());
-
-  BattOrControlMessage* init_msg =
-      reinterpret_cast<BattOrControlMessage*>(GetReadMessage()->data());
-
-  ASSERT_EQ(BATTOR_CONTROL_MESSAGE_TYPE_INIT, init_msg->type);
-  ASSERT_EQ(5, init_msg->param1);
-  ASSERT_EQ(8, init_msg->param2);
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageFailsWithControlButExpectingAck) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,
-      BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-      BATTOR_CONTROL_BYTE_ESCAPE,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-      0x04,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 6);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageFailsWithAckButExpectingControl) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START,         BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-      BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0x04,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 5);
-  ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-TEST_F(BattOrConnectionImplTest, ReadMessageControlTypePrintFails) {
-  OpenConnection();
-  AdvanceTickClock(base::TimeDelta::FromMilliseconds(50));
-
-  const char data[] = {
-      BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_PRINT,
-      BATTOR_CONTROL_BYTE_END,
-  };
-  SendBytesRaw(data, 3);
-  ReadMessage(BATTOR_MESSAGE_TYPE_PRINT);
-
-  ASSERT_TRUE(IsReadComplete());
-  ASSERT_FALSE(GetReadSuccess());
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_error.cc b/tools/battor_agent/battor_error.cc
deleted file mode 100644
index 5575140..0000000
--- a/tools/battor_agent/battor_error.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#include "tools/battor_agent/battor_error.h"
-
-#include "base/logging.h"
-
-namespace battor {
-
-std::string BattOrErrorToString(BattOrError error) {
-  switch (error) {
-    case BATTOR_ERROR_NONE:
-      return "NONE";
-    case BATTOR_ERROR_CONNECTION_FAILED:
-      return "CONNECTION FAILED";
-    case BATTOR_ERROR_TIMEOUT:
-      return "TIMEOUT";
-    case BATTOR_ERROR_SEND_ERROR:
-      return "SEND ERROR";
-    case BATTOR_ERROR_RECEIVE_ERROR:
-      return "RECEIVE ERROR";
-    case BATTOR_ERROR_UNEXPECTED_MESSAGE:
-      return "UNEXPECTED MESSAGE";
-    case BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES:
-      return "TOO MANY COMMAND RETRIES";
-    case BATTOR_ERROR_TOO_MANY_FRAME_RETRIES:
-      return "TOO MANY FRAME RETRIES";
-    case BATTOR_ERROR_FILE_NOT_FOUND:
-      return "FILE NOT FOUND";
-  }
-
-  NOTREACHED();
-  return std::string();
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_error.h b/tools/battor_agent/battor_error.h
deleted file mode 100644
index a8d7fc5..0000000
--- a/tools/battor_agent/battor_error.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_ERROR_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_ERROR_H_
-
-#include <string>
-
-namespace battor {
-
-// A BattOrError is an error that occurs when communicating with a BattOr.
-enum BattOrError {
-  BATTOR_ERROR_NONE,
-  BATTOR_ERROR_CONNECTION_FAILED,
-  BATTOR_ERROR_TIMEOUT,
-  BATTOR_ERROR_SEND_ERROR,
-  BATTOR_ERROR_RECEIVE_ERROR,
-  BATTOR_ERROR_UNEXPECTED_MESSAGE,
-  BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES,
-  BATTOR_ERROR_TOO_MANY_FRAME_RETRIES,
-  BATTOR_ERROR_FILE_NOT_FOUND,
-};
-
-std::string BattOrErrorToString(BattOrError error);
-
-}
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_ERROR_H_
diff --git a/tools/battor_agent/battor_finder.cc b/tools/battor_agent/battor_finder.cc
deleted file mode 100644
index cceb427..0000000
--- a/tools/battor_agent/battor_finder.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-#include "tools/battor_agent/battor_finder.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "device/serial/serial_device_enumerator.h"
-#include "services/device/public/mojom/serial.mojom.h"
-
-namespace battor {
-
-namespace {
-
-// The USB display name prefix that all BattOrs have.
-const char kBattOrDisplayNamePrefix[] = "BattOr";
-
-// The command line switch used to hard-code a BattOr path. Hard-coding
-// this path disables the normal method of finding a BattOr, which is to
-// search through serial devices for one with a matching display name.
-const char kBattOrPathSwitch[] = "battor-path";
-
-}  // namespace
-
-std::string BattOrFinder::FindBattOr() {
-  std::unique_ptr<device::SerialDeviceEnumerator> serial_device_enumerator =
-      device::SerialDeviceEnumerator::Create();
-
-  std::vector<device::mojom::SerialDeviceInfoPtr> devices =
-      serial_device_enumerator->GetDevices();
-
-  std::string switch_specified_path =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          kBattOrPathSwitch);
-  if (switch_specified_path.empty()) {
-    // If we have no switch-specified path, look for a device with the right
-    // display name. See crbug.com/588244 for why this never works on Windows.
-    for (size_t i = 0; i < devices.size(); i++) {
-      if (!devices[i]->display_name)
-        continue;
-      const auto& display_name = devices[i]->display_name.value();
-      if (display_name.find(kBattOrDisplayNamePrefix) != std::string::npos) {
-        LOG(INFO) << "Found BattOr with display name " << display_name
-                  << " at path " << devices[i]->path;
-        return devices[i]->path;
-      }
-    }
-  } else {
-    // If we have a switch-specified path, make sure it actually exists before
-    // returning it.
-    for (size_t i = 0; i < devices.size(); i++) {
-      if (devices[i]->path == switch_specified_path)
-        return switch_specified_path;
-    }
-  }
-
-  return std::string();
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_finder.h b/tools/battor_agent/battor_finder.h
deleted file mode 100644
index 06d24ab9..0000000
--- a/tools/battor_agent/battor_finder.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace battor {
-
-class BattOrFinder {
- public:
-  // Returns the path of the first BattOr that we find.
-  static std::string FindBattOr();
-
-  DISALLOW_COPY_AND_ASSIGN(BattOrFinder);
-};
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_
diff --git a/tools/battor_agent/battor_protocol_types.h b/tools/battor_agent/battor_protocol_types.h
deleted file mode 100644
index 11ac531..0000000
--- a/tools/battor_agent/battor_protocol_types.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_PROTOCOL_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_PROTOCOL_H_
-
-#include <stdint.h>
-
-namespace battor {
-
-// Control characters in the BattOr protocol.
-enum BattOrControlByte : uint8_t {
-  // Indicates the start of a message in the protocol. All other instances of
-  // this byte must be escaped (with BATTOR_SPECIAL_BYTE_ESCAPE).
-  BATTOR_CONTROL_BYTE_START = 0x00,
-  // Indicates the end of a message in the protocol. All other instances of
-  // this byte must be escaped (with BATTOR_SPECIAL_BYTE_ESCAPE).
-  BATTOR_CONTROL_BYTE_END = 0x01,
-  // Indicates that the next byte should not be interpreted as a special
-  // character, but should instead be interpreted as itself.
-  BATTOR_CONTROL_BYTE_ESCAPE = 0x02,
-};
-
-// Types of BattOr messages that can be sent.
-enum BattOrMessageType : uint8_t {
-  // Indicates a control message sent from the client to the BattOr to tell the
-  // BattOr to do something.
-  BATTOR_MESSAGE_TYPE_CONTROL = 0x03,
-  // Indicates a control message ack sent from the BattOr back to the client to
-  // signal that the BattOr received the control message.
-  BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-  // Indicates that the message contains Voltage and current measurements.
-  BATTOR_MESSAGE_TYPE_SAMPLES,
-  // TODO(charliea): Figure out what this is.
-  BATTOR_MESSAGE_TYPE_PRINT,
-};
-
-// Types of BattOr control messages that can be sent.
-enum BattOrControlMessageType : uint8_t {
-  // Tells the BattOr to initialize itself.
-  BATTOR_CONTROL_MESSAGE_TYPE_INIT = 0x00,
-  // Tells the BattOr to reset itself.
-  BATTOR_CONTROL_MESSAGE_TYPE_RESET,
-  // Tells the BattOr to run a self test.
-  BATTOR_CONTROL_MESSAGE_TYPE_SELF_TEST,
-  // Tells the BattOr to send its EEPROM contents over the serial connection.
-  BATTOR_CONTROL_MESSAGE_TYPE_READ_EEPROM,
-  // Sets the current measurement's gain.
-  BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN,
-  // Tells the BattOr to start taking samples and sending them over the
-  // connection.
-  BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_UART,
-  // Tells the BattOr to start taking samples and storing them on its SD card.
-  BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD,
-  // Tells the BattOr to start streaming the samples stored on its SD card over
-  // the connection.
-  BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART,
-  // Tells the BattOr to send back the number of samples it's collected so far.
-  // This is used for syncing the clocks between the agent and the BattOr.
-  BATTOR_CONTROL_MESSAGE_TYPE_READ_SAMPLE_COUNT,
-  // Tells the BattOr to send back the git hash of the firmware.
-  BATTOR_CONTROL_MESSAGE_TYPE_GET_FIRMWARE_GIT_HASH,
-  // Read if the BattOr is portable or not.
-  BATTOR_CONTROL_MESSAGE_TYPE_GET_MODE_PORTABLE,
-  // Write the RTC seconds.
-  BATTOR_CONTROL_MESSAGE_TYPE_SET_RTC,
-  // Read the RTC seconds.
-  BATTOR_CONTROL_MESSAGE_TYPE_GET_RTC,
-};
-
-// The gain level for the BattOr to use.
-enum BattOrGain : uint8_t { BATTOR_GAIN_LOW = 0, BATTOR_GAIN_HIGH };
-
-// The data types below are packed to ensure byte-compatibility with the BattOr
-// firmware.
-#pragma pack(push, 1)
-
-// See: BattOrMessageType::BATTOR_MESSAGE_TYPE_CONTROL above.
-struct BattOrControlMessage {
-  BattOrControlMessageType type;
-  uint16_t param1;
-  uint16_t param2;
-};
-
-// See: BattOrMessageType::BATTOR_MESSAGE_TYPE_CONTROL_ACK above.
-struct BattOrControlMessageAck {
-  BattOrControlMessageType type;
-  uint8_t param;
-};
-
-// TODO(charliea, aschulman): Write better descriptions for the EEPROM fields
-// when we actually start doing the math to convert raw BattOr readings to
-// accurate ones.
-
-// The BattOr's EEPROM is persistent storage that contains information that we
-// need in order to convert raw BattOr readings into accurate voltage and
-// current measurements.
-struct BattOrEEPROM {
-  uint8_t magic[4];
-  uint16_t version;
-  char serial_num[20];
-  uint32_t timestamp;
-  float r1;
-  float r2;
-  float r3;
-  float low_gain;
-  float low_gain_correction_factor;
-  float low_gain_correction_offset;
-  uint16_t low_gain_amppot;
-  float high_gain;
-  float high_gain_correction_factor;
-  float high_gain_correction_offset;
-  uint16_t high_gain_amppot;
-  uint32_t sd_sample_rate;
-  uint16_t sd_tdiv;
-  uint16_t sd_tovf;
-  uint16_t sd_filpot;
-  uint32_t uart_sr;
-  uint16_t uart_tdiv;
-  uint16_t uart_tovf;
-  uint16_t uart_filpot;
-  uint32_t crc32;
-};
-
-// The BattOrFrameHeader begins every frame containing BattOr samples.
-struct BattOrFrameHeader {
-  // The number of frames that have preceded this one.
-  uint32_t sequence_number;
-  // The number of bytes of raw samples in this frame.
-  uint16_t length;
-};
-
-// A single BattOr sample. These samples are raw because they come directly from
-// the BattOr's analog to digital converter and comprise only part of the
-// equation to calculate meaningful voltage and current measurements.
-struct RawBattOrSample {
-  int16_t voltage_raw;
-  int16_t current_raw;
-};
-
-// A single BattOr sample after timestamp assignment and conversion to unitful
-// numbers.
-struct BattOrSample {
-  double time_ms;
-  double voltage_mV;
-  double current_mA;
-};
-
-#pragma pack(pop)
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_PROTOCOL_H_
diff --git a/tools/battor_agent/battor_protocol_types_unittest.cc b/tools/battor_agent/battor_protocol_types_unittest.cc
deleted file mode 100644
index cdd9ec1..0000000
--- a/tools/battor_agent/battor_protocol_types_unittest.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/battor_agent/battor_protocol_types.h"
-
-#include <iostream>
-#include <string>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/battor_agent/serial_utils.h"
-
-using namespace testing;
-
-namespace battor {
-
-namespace {
-
-const BattOrEEPROM kUnserializedEEPROM{
-    {0, 0, 0, 1}, 2,  "serialno", 3,  4,  5,  6,  7,  8,  9,  10, 11,
-    12,           13, 14,         15, 16, 17, 18, 19, 20, 21, 22, 24,
-};
-
-// The serialized version of the above EEPROM.
-const unsigned char kSerializedEEPROM[] = {
-    0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
-    0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
-    0xa0, 0x40, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0xe0, 0x40, 0x00, 0x00,
-    0x00, 0x41, 0x00, 0x00, 0x10, 0x41, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x41,
-    0x00, 0x00, 0x40, 0x41, 0x00, 0x00, 0x50, 0x41, 0x0e, 0x00, 0x0f, 0x00,
-    0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x00, 0x00,
-    0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x00, 0x00,
-};
-
-}  // namespace
-
-TEST(BattOrProtocolTypeTest, EEPROMSerializesCorrectly) {
-  // The easier way to write this test would be using memcmp. However, because
-  // the EEPROM will change in the future and we'll need to update the
-  // serialized version when it does, it makes sense to print the bytes as a
-  // string that can just be copied and pasted into kSerializedEEPROM.
-  const char* eeprom_bytes =
-      reinterpret_cast<const char*>(&kUnserializedEEPROM);
-
-  ASSERT_EQ(CharArrayToString(reinterpret_cast<const char*>(kSerializedEEPROM),
-                              sizeof(kSerializedEEPROM)),
-            CharArrayToString(eeprom_bytes, sizeof(kUnserializedEEPROM)));
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_sample_converter.cc b/tools/battor_agent/battor_sample_converter.cc
deleted file mode 100644
index efbf046..0000000
--- a/tools/battor_agent/battor_sample_converter.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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.
-
-#include "battor_sample_converter.h"
-
-#include <stdlib.h>
-
-namespace battor {
-
-namespace {
-
-// The analog to digital converts an analog signal to a signed 12 bit integer,
-// meaning that it can output numbers in the range [-2048, 2047].
-const int16_t kAnalogDigitalConverterMinValue = -2048;
-const int16_t kAnalogDigitalConverterMaxValue = 2047;
-
-// The maximum voltage that the BattOr is capable of measuring.
-const double kMaxVoltage = 1.2;
-
-// Converts a raw voltage to a unitful one.
-double ToUnitfulVoltage(double voltage_raw) {
-  // Raw voltage samples are collected directly from the BattOr's analog to
-  // digital converter, which converts numbers in the domain [-1.2V, 1.2V] to
-  // numbers in the range [-2048, 2047]. A zero voltage has the same meaning in
-  // both the domain and range. Because of this, one negative unit in that range
-  // represents a slightly smaller domain (1.2 / 2048) than one positive unit
-  // in that range (1.2 / 2047). We take this into account when reversing the
-  // transformation here.
-  int16_t extreme_value = voltage_raw >= 0 ? kAnalogDigitalConverterMaxValue
-                                           : kAnalogDigitalConverterMinValue;
-
-  return voltage_raw / abs(extreme_value) * kMaxVoltage;
-}
-
-}  // namespace
-
-BattOrSampleConverter::BattOrSampleConverter(
-    const BattOrEEPROM& eeprom,
-    const std::vector<RawBattOrSample>& calibration_frame)
-    : eeprom_(eeprom) {
-  baseline_current_ = baseline_voltage_ = 0;
-  for (auto sample : calibration_frame) {
-    baseline_current_ += ToUnitfulVoltage(sample.current_raw);
-    baseline_voltage_ += ToUnitfulVoltage(sample.voltage_raw);
-  }
-
-  baseline_current_ /= calibration_frame.size();
-  baseline_voltage_ /= calibration_frame.size();
-}
-
-BattOrSampleConverter::~BattOrSampleConverter() = default;
-
-BattOrSample BattOrSampleConverter::ToSample(const RawBattOrSample& sample,
-                                             size_t sample_number) const {
-  // Subtract out the baseline current and voltage that the BattOr reads even
-  // when it's not attached to anything.
-  double current = ToUnitfulVoltage(sample.current_raw) - baseline_current_;
-  double voltage = ToUnitfulVoltage(sample.voltage_raw) - baseline_voltage_;
-
-  // The BattOr has to amplify the voltage so that it's on a similar scale as
-  // the reference voltage. This is done in the circuit using resistors (with
-  // known resistances r2 and r3). Here we undo that amplification.
-  double voltage_divider = eeprom_.r3 / (eeprom_.r2 + eeprom_.r3);
-  voltage /= voltage_divider;
-
-  // Convert to millivolts.
-  voltage *= 1000;
-
-  // The BattOr multiplies the current by the gain, so we have to undo that
-  // amplification, too.
-  current /= eeprom_.low_gain;
-
-  // The current is measured indirectly and is actually given to us as a voltage
-  // across a resistor with a known resistance r1. Because
-  //
-  //   V (voltage) = i (current) * R (resistance)
-  //
-  // we can get the current by dividing this voltage by the resistance.
-  current /= eeprom_.r1;
-
-  // Convert to milliamps.
-  current *= 1000;
-
-  // Each BattOr is individually factory-calibrated. Apply these calibrations.
-  current -= eeprom_.low_gain_correction_offset;
-  current /= eeprom_.low_gain_correction_factor;
-
-  double time_ms = double(sample_number) / eeprom_.sd_sample_rate * 1000;
-
-  return BattOrSample{time_ms, voltage, current};
-}
-
-float BattOrSampleConverter::ToWatts(const RawBattOrSample& raw_sample) const {
-  BattOrSample sample = ToSample(raw_sample, 0);
-
-  return sample.current_mA * sample.voltage_mV * 1e-6f;
-}
-
-BattOrSample BattOrSampleConverter::MinSample() const {
-  // Create a minimum raw sample.
-  RawBattOrSample sample_raw = {kAnalogDigitalConverterMinValue,
-                                kAnalogDigitalConverterMinValue};
-  return ToSample(sample_raw, 0);
-}
-
-BattOrSample BattOrSampleConverter::MaxSample() const {
-  // Create a maximum raw sample.
-  RawBattOrSample sample_raw = {kAnalogDigitalConverterMaxValue,
-                                kAnalogDigitalConverterMaxValue};
-  return ToSample(sample_raw, 0);
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/battor_sample_converter.h b/tools/battor_agent/battor_sample_converter.h
deleted file mode 100644
index 23915e9..0000000
--- a/tools/battor_agent/battor_sample_converter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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.
-
-#ifndef TOOLS_BATTOR_AGENT_BATTOR_SAMPLE_CONVERTER_H_
-#define TOOLS_BATTOR_AGENT_BATTOR_SAMPLE_CONVERTER_H_
-
-#include <stddef.h>
-#include <vector>
-
-#include "base/macros.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-namespace battor {
-
-// Converter capable of taking raw samples from the BattOr and using
-// configuration information to turn them into samples with real units.
-class BattOrSampleConverter {
- public:
-  // Constructs a BattOrSampleConverter.
-  //
-  //   - eeprom: The BattOr's EEPROM, which contains some required conversion
-  //     parameters.
-  //   - calibration_frame: The first frame sent back from the BattOr when
-  //     streaming samples. This frame gives current and voltage measurements
-  //     that ignore whatever the BattOr's connected to, and therefore provide
-  //     a means for us to determine baseline current and voltage.
-  BattOrSampleConverter(const BattOrEEPROM& eeprom,
-                        const std::vector<RawBattOrSample>& calibration_frame);
-  virtual ~BattOrSampleConverter();
-
-  // Converts a raw sample to a unitful one with a timestamp.
-  BattOrSample ToSample(const RawBattOrSample& sample,
-                        size_t sample_number) const;
-
-  // Converts a raw sample to watts.
-  float ToWatts(const RawBattOrSample& sample) const;
-
-  // Returns the lowest magnitude sample that the BattOr can collect.
-  BattOrSample MinSample() const;
-
-  // Returns the highest magnitude sample that the BattOr can collect.
-  BattOrSample MaxSample() const;
-
- private:
-  // The BattOr's EEPROM, which stores some conversion parameters we need.
-  BattOrEEPROM eeprom_;
-
-  // The baseline current and voltage calculated from the calibration frame.
-  double baseline_current_;
-  double baseline_voltage_;
-
-  DISALLOW_COPY_AND_ASSIGN(BattOrSampleConverter);
-};
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_BATTOR_SAMPLE_CONVERTER_H_
diff --git a/tools/battor_agent/battor_sample_converter_unittest.cc b/tools/battor_agent/battor_sample_converter_unittest.cc
deleted file mode 100644
index 01ad5e5..0000000
--- a/tools/battor_agent/battor_sample_converter_unittest.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// 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.
-
-#include "tools/battor_agent/battor_sample_converter.h"
-
-#include <vector>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/battor_agent/battor_protocol_types.h"
-
-using namespace testing;
-
-namespace battor {
-
-TEST(BattOrSampleConverterTest, ToSampleSimple) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 1.0f;
-  eeprom.r2 = 1.0f;
-  eeprom.r3 = 1.0f;
-  eeprom.low_gain = 1.0f;
-  eeprom.low_gain_correction_offset = 0.0f;
-  eeprom.low_gain_correction_factor = 1.0f;
-  eeprom.sd_sample_rate = 1000;
-
-  // Create a calibration frame with a baseline voltage and current of zero.
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{0, 0});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  // Set both the voltage and current to their max values.
-  RawBattOrSample raw_one{2048, 2048};
-  BattOrSample one = converter.ToSample(raw_one, 0);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(2401.172447484123, one.voltage_mV);
-  ASSERT_DOUBLE_EQ(1200.5862237420615, one.current_mA);
-}
-
-TEST(BattOrSampleConverterTest, ToSampleNonZeroBaseline) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 1.0f;
-  eeprom.r2 = 1.0f;
-  eeprom.r3 = 1.0f;
-  eeprom.low_gain = 1.0f;
-  eeprom.low_gain_correction_offset = 0.0f;
-  eeprom.low_gain_correction_factor = 1.0f;
-  eeprom.sd_sample_rate = 1000;
-
-  // Create a calibration frame with a baseline voltage and current of zero.
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{1024, 1024});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  // Set both the voltage and current to their max values.
-  RawBattOrSample raw_one{2048, 2048};
-  BattOrSample one = converter.ToSample(raw_one, 0);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(1200.586223742061, one.voltage_mV);
-  ASSERT_DOUBLE_EQ(600.29311187103076, one.current_mA);
-}
-
-TEST(BattOrSampleConverterTest, ToSampleNonZeroMultiSampleBaseline) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 1.0f;
-  eeprom.r2 = 1.0f;
-  eeprom.r3 = 1.0f;
-  eeprom.low_gain = 1.0f;
-  eeprom.low_gain_correction_offset = 0.0f;
-  eeprom.low_gain_correction_factor = 1.0f;
-  eeprom.sd_sample_rate = 1000;
-
-  // Create a calibration frame with a baseline voltage and current of zero.
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{1000, 1000});
-  calibration_frame.push_back(RawBattOrSample{1048, 1048});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  // Set both the voltage and current to their max values.
-  RawBattOrSample raw_one{2048, 2048};
-  BattOrSample one = converter.ToSample(raw_one, 0);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(1200.5862237420615, one.voltage_mV);
-  ASSERT_DOUBLE_EQ(600.29311187103076, one.current_mA);
-}
-
-TEST(BattOrSampleConverterTest, ToSampleRealValues) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 10.0f;
-  eeprom.r2 = 14.0f;
-  eeprom.r3 = 17.0f;
-  eeprom.low_gain = 1.5;
-  eeprom.low_gain_correction_offset = 0.03f;
-  eeprom.low_gain_correction_factor = 4.0f;
-  eeprom.sd_sample_rate = 1000;
-
-  // Create a calibration frame with a baseline voltage and current of zero.
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{800, 900});
-  calibration_frame.push_back(RawBattOrSample{1000, 1100});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  // Set both the voltage and current to their max values.
-  RawBattOrSample raw_one{1900, 2000};
-  BattOrSample one = converter.ToSample(raw_one, 0);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(1068.996209287540, one.voltage_mV);
-  ASSERT_DOUBLE_EQ(9.7628957011935285, one.current_mA);
-}
-
-TEST(BattOrSampleConverterTest, ToSampleRealNegativeValues) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 10.0f;
-  eeprom.r2 = 14.0f;
-  eeprom.r3 = 17.0f;
-  eeprom.low_gain = 1.5;
-  eeprom.low_gain_correction_offset = 0.03f;
-  eeprom.low_gain_correction_factor = 4.0f;
-  eeprom.sd_sample_rate = 1000;
-
-  // Create a calibration frame with a baseline voltage and current of zero.
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{800, 900});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  // Set both the voltage and current to their max values.
-  RawBattOrSample raw_one{-1900, -2000};
-  BattOrSample one = converter.ToSample(raw_one, 0);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(-2885.2980205462577, one.voltage_mV);
-  ASSERT_DOUBLE_EQ(-28.332106130755665, one.current_mA);
-}
-
-TEST(BattOrSampleConverterTest, ToSampleMultipleSamples) {
-  BattOrEEPROM eeprom;
-  eeprom.r1 = 1.0f;
-  eeprom.r2 = 1.0f;
-  eeprom.r3 = 1.0f;
-  eeprom.low_gain = 1.0f;
-  eeprom.low_gain_correction_offset = 0.0f;
-  eeprom.low_gain_correction_factor = 1.0f;
-  eeprom.sd_sample_rate = 50;
-
-  std::vector<RawBattOrSample> calibration_frame;
-  calibration_frame.push_back(RawBattOrSample{0, 0});
-  BattOrSampleConverter converter(eeprom, calibration_frame);
-
-  BattOrSample one = converter.ToSample(RawBattOrSample{0, 0}, 0);
-  BattOrSample two = converter.ToSample(RawBattOrSample{0, 0}, 1);
-  BattOrSample three = converter.ToSample(RawBattOrSample{0, 0}, 2);
-
-  ASSERT_DOUBLE_EQ(0, one.time_ms);
-  ASSERT_DOUBLE_EQ(20, two.time_ms);
-  ASSERT_DOUBLE_EQ(40, three.time_ms);
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/serial_utils.cc b/tools/battor_agent/serial_utils.cc
deleted file mode 100644
index 314d714..0000000
--- a/tools/battor_agent/serial_utils.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#include "tools/battor_agent/serial_utils.h"
-
-namespace battor {
-
-std::string ByteVectorToString(const std::vector<uint8_t>& data) {
-  std::string s;
-
-  // Reserve enough bytes for '0x', the two data characters, a space, and a null
-  // terminating byte.
-  char num_buff[6];
-  for (uint8_t d : data) {
-    // We use sprintf because stringstream's hex support wants to print our
-    // characters as signed.
-    sprintf(num_buff, "0x%02hhx ", d);
-    s += num_buff;
-  }
-
-  return s.substr(0, s.size() - 1);
-}
-
-std::string CharArrayToString(const char* bytes, size_t len) {
-  return ByteVectorToString(std::vector<uint8_t>(bytes, bytes + len));
-}
-
-}  // namespace battor
diff --git a/tools/battor_agent/serial_utils.h b/tools/battor_agent/serial_utils.h
deleted file mode 100644
index 560b9768..0000000
--- a/tools/battor_agent/serial_utils.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#ifndef TOOLS_BATTOR_AGENT_SERIAL_UTILS_H_
-#define TOOLS_BATTOR_AGENT_SERIAL_UTILS_H_
-
-#include <string>
-#include <vector>
-
-namespace battor {
-
-// Prints |bytes| as a space separated list of hex numbers (e.g. {'A', 'J'}
-// would return "0x41 0x4A").
-std::string CharArrayToString(const char* bytes, size_t len);
-std::string ByteVectorToString(const std::vector<uint8_t>& bytes);
-
-}  // namespace battor
-
-#endif  // TOOLS_BATTOR_AGENT_SERIAL_UTILS_H_
diff --git a/tools/battor_agent/serial_utils_unittest.cc b/tools/battor_agent/serial_utils_unittest.cc
deleted file mode 100644
index 2f17653f..0000000
--- a/tools/battor_agent/serial_utils_unittest.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#include "tools/battor_agent/serial_utils.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace testing;
-
-namespace battor {
-
-TEST(SerialUtilsTest, ByteVectorToStringLengthZero) {
-  EXPECT_EQ("", ByteVectorToString(std::vector<uint8_t>()));
-}
-
-TEST(SerialUtilsTest, ByteVectorToStringLengthOne) {
-  EXPECT_EQ("0x41", ByteVectorToString(std::vector<uint8_t>({'A'})));
-}
-
-TEST(SerialUtilsTest, ByteVectorToStringLengthTwo) {
-  EXPECT_EQ("0x41 0x4a", ByteVectorToString(std::vector<uint8_t>({'A', 'J'})));
-}
-
-TEST(SerialUtilsTest, CharArrayToStringLengthOne) {
-  const char arr[] = {'A'};
-  EXPECT_EQ("0x41", CharArrayToString(arr, sizeof(arr)));
-}
-
-TEST(SerialUtilsTest, CharArrayToStringLengthTwo) {
-  const char arr[] = {'A', 'J'};
-  EXPECT_EQ("0x41 0x4a", CharArrayToString(arr, sizeof(arr)));
-}
-
-}  // namespace battor
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index ad6fc41c..cc10768e 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -146,10 +146,15 @@
 
     # See comment in _CalculatePadding() about when this can happen. Don't
     # process names for non-native sections.
-    if (full_name.startswith('*') or
+    if symbol.IsPak():
+      # full_name: "about_ui_resources.grdp: IDR_ABOUT_UI_CREDITS_HTML".
+      space_idx = full_name.rindex(' ')
+      name = full_name[space_idx + 1:]
+      symbol.template_name = name
+      symbol.name = name
+    elif (full_name.startswith('*') or
         symbol.IsOverhead() or
-        symbol.IsOther() or
-        symbol.IsPak()):
+        symbol.IsOther()):
       symbol.template_name = full_name
       symbol.name = full_name
     elif symbol.IsDex():
@@ -685,10 +690,10 @@
   return ret
 
 
-def LoadAndPostProcessSizeInfo(path, fileobj=None):
+def LoadAndPostProcessSizeInfo(path, file_obj=None):
   """Returns a SizeInfo for the given |path|."""
   logging.debug('Loading results from: %s', path)
-  size_info = file_format.LoadSizeInfo(path, fileobj)
+  size_info = file_format.LoadSizeInfo(path, file_obj=file_obj)
   logging.info('Normalizing symbol names')
   _NormalizeNames(size_info.raw_symbols)
   logging.info('Calculating padding')
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py
index 793754b..0915f99 100644
--- a/tools/binary_size/libsupersize/diff.py
+++ b/tools/binary_size/libsupersize/diff.py
@@ -39,13 +39,18 @@
     "._468", "._467"
     ".L__unnamed_1193", ".L__unnamed_712"
   """
-  name = _STRIP_NUMBER_SUFFIX_PATTERN.sub('', symbol.full_name)
-  clone_idx = name.find(' [clone ')
-  if clone_idx != -1:
-    name = name[:clone_idx]
-  if name.startswith('*'):
-    # "symbol gap 3 (bar)" -> "symbol gaps"
-    name = _NORMALIZE_STAR_SYMBOLS_PATTERN.sub('s', name)
+  if symbol.IsPak():
+    # full_name looks like "about_ui_resources.grdp: IDR_ABOUT_UI_CREDITS_HTML".
+    # name is just "IDR_ABOUT_UI_CREDITS_HTML".
+    name = symbol.name
+  else:
+    name = _STRIP_NUMBER_SUFFIX_PATTERN.sub('', symbol.full_name)
+    clone_idx = name.find(' [clone ')
+    if clone_idx != -1:
+      name = name[:clone_idx]
+    if name.startswith('*'):
+      # "symbol gap 3 (bar)" -> "symbol gaps"
+      name = _NORMALIZE_STAR_SYMBOLS_PATTERN.sub('s', name)
 
   return symbol.section, symbol.object_path, name
 
diff --git a/tools/binary_size/libsupersize/file_format.py b/tools/binary_size/libsupersize/file_format.py
index 23d31fc..db534e0 100644
--- a/tools/binary_size/libsupersize/file_format.py
+++ b/tools/binary_size/libsupersize/file_format.py
@@ -341,17 +341,21 @@
 
 
 @contextlib.contextmanager
-def _OpenGzipForWrite(path):
+def _OpenGzipForWrite(path, file_obj=None):
   # Open in a way that doesn't set any gzip header fields.
-  with open(path, 'wb') as f:
-    with gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0) as fz:
+  if file_obj:
+    with gzip.GzipFile(filename='', mode='wb', fileobj=file_obj, mtime=0) as fz:
       yield fz
+  else:
+    with open(path, 'wb') as f:
+      with gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0) as fz:
+        yield fz
 
 
-def SaveSizeInfo(size_info, path):
+def SaveSizeInfo(size_info, path, file_obj=None):
   """Saves |size_info| to |path}."""
   if os.environ.get('SUPERSIZE_MEASURE_GZIP') == '1':
-    with _OpenGzipForWrite(path) as f:
+    with _OpenGzipForWrite(path, file_obj=file_obj) as f:
       _SaveSizeInfoToFile(size_info, f)
   else:
     # It is seconds faster to do gzip in a separate step. 6s -> 3.5s.
@@ -360,11 +364,11 @@
 
     logging.debug('Serialization complete. Gzipping...')
     stringio.seek(0)
-    with _OpenGzipForWrite(path) as f:
+    with _OpenGzipForWrite(path, file_obj=file_obj) as f:
       shutil.copyfileobj(stringio, f)
 
 
-def LoadSizeInfo(filename, fileobj=None):
+def LoadSizeInfo(filename, file_obj=None):
   """Returns a SizeInfo loaded from |filename|."""
-  with gzip.GzipFile(filename=filename, fileobj=fileobj) as f:
+  with gzip.GzipFile(filename=filename, fileobj=file_obj) as f:
     return _LoadSizeInfoFromFile(f, filename)
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 01c6343..a7e7f82 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import cStringIO
 import contextlib
 import copy
 import difflib
@@ -326,8 +327,8 @@
 
   @_CompareWithGolden()
   def test_Diff_Basic(self):
-    size_info1 = self._CloneSizeInfo(use_elf=False)
-    size_info2 = self._CloneSizeInfo(use_elf=False)
+    size_info1 = self._CloneSizeInfo(use_elf=False, use_pak=True)
+    size_info2 = self._CloneSizeInfo(use_elf=False, use_pak=True)
     size_info1.metadata = {"foo": 1, "bar": [1,2,3], "baz": "yes"}
     size_info2.metadata = {"foo": 1, "bar": [1,3], "baz": "yes"}
 
@@ -338,16 +339,30 @@
     padding_sym = size_info2.raw_symbols.WhereNameMatches('symbol gap 0')[0]
     padding_sym.padding += 20
     padding_sym.size += 20
+    pak_sym = size_info2.raw_symbols.WhereInSection(
+        models.SECTION_PAK_TRANSLATIONS)[0]
+    pak_sym.full_name = 'foo: ' + pak_sym.full_name.split()[-1]
+
+    # Serialize & de-serialize so that name normalization runs again for the pak
+    # symbol.
+    stringio = cStringIO.StringIO()
+    file_format.SaveSizeInfo(size_info2, 'path', file_obj=stringio)
+    stringio.seek(0)
+    size_info2 = archive.LoadAndPostProcessSizeInfo('path', file_obj=stringio)
+
     d = diff.Diff(size_info1, size_info2)
     d.raw_symbols = d.raw_symbols.Sorted()
     self.assertEquals(d.raw_symbols.CountsByDiffStatus()[1:], [2, 2, 3])
     changed_sym = d.raw_symbols.WhereNameMatches('Patcher::Name_')[0]
     padding_sym = d.raw_symbols.WhereNameMatches('symbol gap 0')[0]
+    bss_sym = d.raw_symbols.WhereInSection(models.SECTION_BSS)[0]
     # Padding-only deltas should sort after all non-padding changes.
     padding_idx = d.raw_symbols.index(padding_sym)
-    self.assertLess(d.raw_symbols.index(changed_sym), padding_idx)
+    changed_idx = d.raw_symbols.index(changed_sym)
+    bss_idx = d.raw_symbols.index(bss_sym)
+    self.assertLess(changed_idx, padding_idx)
     # And before bss.
-    self.assertTrue(d.raw_symbols[padding_idx + 1].IsBss())
+    self.assertLess(padding_idx, bss_idx)
 
     return describe.GenerateLines(d, verbose=True)
 
diff --git a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
index 65e3c5c..c6ee462 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
@@ -10,6 +10,7 @@
     .bss: 0 bytes (0 bytes) (not included in totals)
     .data: 0 bytes (0 bytes) (0.0%)
     .data.rel.ro: 0 bytes (0 bytes) (0.0%)
+    .pak.translations: 0 bytes (0 bytes) (0.0%)
     .rel.dyn: 0 bytes (0 bytes) (0.0%)
     .rodata: 0 bytes (0 bytes) (0.0%)
     .text: 0 bytes (0 bytes) (0.0%)
@@ -38,42 +39,45 @@
     .strtab: 0 bytes (0 bytes)
     .symtab: 0 bytes (0 bytes)
 
-2 symbols added (+), 2 changed (~), 3 removed (-), 34 unchanged (not shown)
-Of changed symbols, 4 grew, 3 shrank
-Number of unique symbols 44 -> 43 (-1)
+2 symbols added (+), 2 changed (~), 3 removed (-), 242 unchanged (not shown)
+Of changed symbols, 3 grew, 4 shrank
+Number of unique symbols 251 -> 250 (-1)
 0 paths added, 0 removed, 2 changed
 Changed files:
   
   third_party/container/container.c
 
-Showing 7 symbols (5 -> 4 unique) with total pss: 38 bytes
+Showing 7 symbols (5 -> 4 unique) with total pss: -112 bytes
 Histogram of symbols based on PSS:
-    (-256,-128]: 1   (-32,-16]: 1   (-8,-4]: 1   [4,8): 2   [8,16): 1   [16,32): 1
-.text=0 bytes    .rodata=10 bytes   .data.rel.ro=0 bytes    .data=28 bytes   .bss=-232 bytes total=38 bytes
-Number of unique paths: 4
+    (-128,-64]: 1   (-32,-16]: 2   (-16,-8]: 1   [4,8): 2   [8,16): 1
+.text=0 bytes    .rodata=10 bytes   .data.rel.ro=0 bytes    .data=8 bytes    .bss=0 bytes    .pak.translations=-130 bytes total=-112 bytes
+Number of unique paths: 3
 
-Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss
+Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, p=.pak.translations
 Index | Running Total | Section@Address | ...
 ------------------------------------------------------------
-~ 0)         10 (26.3%) r@0x284e398  +10 (22->32)  num_aliases=1
+- 0)        -80 (71.4%) p@0x0        -80 (80->0)  num_aliases=1
+               source_path= 	object_path=
+               flags={}  name=IDS_AW_WEBPAGE_PARENTAL_PERMISSION_NEEDED
+                    full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_PARENTAL_PERMISSION_NEEDED
+- 1)       -103 (92.0%) p@0x0        -23 (23->0)  num_aliases=1
+               source_path= 	object_path=
+               flags={}  name=IDS_WEB_FONT_FAMILY
+                    full_name=../../ui/strings/app_locale_settings.grd: IDS_WEB_FONT_FAMILY
+- 2)       -112 (100.0%) p@0x0        -9 (9->0)  num_aliases=1
+               source_path= 	object_path=
+               flags={}  name=IDS_WEB_FONT_SIZE
+                    full_name=../../ui/strings/app_locale_settings.grd: IDS_WEB_FONT_SIZE
+~ 3)       -130 (116.1%) p@0x0        -18 (0->0)  num_aliases=1
+               source_path= 	object_path=
+               flags={}  name=../../../mock_apk/assets/en-US.pak
+                    full_name=foo: ../../../mock_apk/assets/en-US.pak
+~ 4)       -120 (107.1%) r@0x284e398  +10 (22->32)  num_aliases=1
                source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
                flags={}  name=chrome::mojom::FilePatcher::Name_
-+ 1)         14 (36.8%) d@0x2de7000  +4 (0->4)  num_aliases=1
++ 5)       -116 (103.6%) d@0x2de7000  +4 (0->4)  num_aliases=1
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=google::protobuf::internal::pLinuxKernelCmpxchg
-+ 2)         18 (47.4%) d@0x2de7004  +4 (0->4)  num_aliases=1
++ 6)       -112 (100.0%) d@0x2de7004  +4 (0->4)  num_aliases=1
                source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
                flags={}  name=google::protobuf::internal::pLinuxKernelMemoryBarrier
-~ 3)         38 (100.0%) d@0x2dffd88  20 (0->0)  num_aliases=1
-               source_path= 	object_path=
-               flags={}  name=** symbol gap 0 (end of section)
-- 4)         38 (100.0%) b@0x0        -200 (4->0)  num_aliases=1
-               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
-               flags={gen}  name=SaveHistogram::atomic_histogram_pointer
-                    full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
-- 5)         38 (100.0%) b@0x0        -28 (28->0)  num_aliases=1
-               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
-               flags={gen}  name=g_chrome_content_browser_client
-- 6)         38 (100.0%) b@0x0        -4 (4->0)  num_aliases=1
-               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
-               flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index f1e51a1..3003d55 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -461,6 +461,9 @@
     'third_party/modp_b64': [
         'UNKNOWN',
     ],
+    'third_party/nvml': [
+        'UNKNOWN',
+    ],
     # Missing license headers in openh264 sources: https://github.com/cisco/openh264/issues/2233
     'third_party/openh264/src': [
         'UNKNOWN',
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index ead68d3..5a4707c 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -8,6 +8,7 @@
 
 import argparse
 import fnmatch
+import glob
 import itertools
 import os
 import shutil
@@ -383,6 +384,23 @@
             filter=PrintTarProgress)
   MaybeUpload(args, cfiverifydir, platform)
 
+  # Zip up the SafeStack runtime for Linux
+  safestackdir = 'safestack-' + stamp
+  shutil.rmtree(safestackdir, ignore_errors=True)
+  os.makedirs(os.path.join(safestackdir, 'lib'))
+  for build in glob.glob(os.path.join(LLVM_RELEASE_DIR, 'lib', 'clang', '*')):
+    version = os.path.basename(build)
+    dest_dir = os.path.join(safestackdir, 'lib', 'clang', version,
+                            'lib', 'linux')
+    os.makedirs(dest_dir)
+    for lib in glob.glob(os.path.join(build, 'lib', 'linux',
+                                      '*libclang_rt.safestack*')):
+      shutil.copy(lib, dest_dir)
+  with tarfile.open(safestackdir + '.tgz', 'w:gz') as tar:
+    tar.add(os.path.join(safestackdir, 'lib'), arcname='lib',
+            filter=PrintTarProgress)
+  MaybeUpload(args, safestackdir, platform)
+
   # On Mac, lld isn't part of the main zip.  Upload it in a separate zip.
   if sys.platform == 'darwin':
     llddir = 'lld-' + stamp
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index f8dd093..b30818d 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -39,7 +39,6 @@
     'ar_sample_test_driver',
     'audio_unittests',
     'base_unittests',
-    'battor_agent_unittests',
     'blink_heap_unittests',
     'blink_platform_perftests',
     'blink_platform_unittests',
diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py
index 59ff535f..d777019 100755
--- a/tools/grit/grit/format/html_inline.py
+++ b/tools/grit/grit/format/html_inline.py
@@ -28,6 +28,9 @@
 mimetypes.init([])
 mimetypes.add_type('image/svg+xml', '.svg')
 
+# webm video type is not always available if mimetype package is outdated.
+mimetypes.add_type('video/webm', '.webm')
+
 DIST_DEFAULT = 'chromium'
 DIST_ENV_VAR = 'CHROMIUM_BUILD'
 DIST_SUBSTR = '%DISTRIBUTION%'
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index f4f9380e..10f4687d 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -377,9 +377,6 @@
       'Android arm64 Builder Perf FYI': 'official_goma_minimal_symbols_android_arm64',
       'Android CFI Builder Perf FYI': 'official_goma_minimal_symbols_android_thin_lto',
       'Android CFI arm64 Builder Perf FYI': 'official_goma_minimal_symbols_android_thin_lto_arm64',
-      'Battor Agent Linux': 'release_bot',
-      'Battor Agent Mac': 'release_bot',
-      'Battor Agent Win': 'release_bot',
       'Mac Builder Perf FYI': 'official_goma',
       'Win Builder Perf FYI': 'official_goma_x86',
     },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d27c545d..c7c6693d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -19260,7 +19260,6 @@
   <int value="2230" label="ReplaceCharsetInXHR"/>
   <int value="2231" label="RespondToSameOriginRequestWithCrossOriginResponse"/>
   <int value="2232" label="LinkRelModulePreload"/>
-  <int value="2235" label="HTMLFrameSetElementNonNullAnonymousNamedGetter"/>
   <int value="2236" label="CSPWithUnsafeEval"/>
   <int value="2237" label="WebAssemblyInstantiation"/>
   <int value="2238" label="V8IndexAccessor"/>
@@ -19500,7 +19499,6 @@
   <int value="2461" label="ShapeOutsideContentBoxDifferentFromMarginBox"/>
   <int value="2462" label="ShapeOutsidePaddingBoxDifferentFromMarginBox"/>
   <int value="2463" label="CSSContainLayoutPositionedDescendants"/>
-  <int value="2464" label="HTMLFrameSetElementAnonymousNamedGetter"/>
   <int value="2465" label="CanvasConvertToBlob"/>
   <int value="2466" label="PolymerV1Detected"/>
   <int value="2467" label="PolymerV2Detected"/>
@@ -28607,6 +28605,7 @@
   <int value="-141516902" label="UseModernMediaControls:enabled"/>
   <int value="-138983372" label="DesktopPWAWindowing:disabled"/>
   <int value="-138773929" label="PassiveDocumentEventListeners:enabled"/>
+  <int value="-137303226" label="enable-chromevox-developer-option"/>
   <int value="-135223364" label="AutofillShowTypePredictions:disabled"/>
   <int value="-127231994" label="VrBrowsingNativeAndroidUi:disabled"/>
   <int value="-122492389" label="enable-browser-task-scheduler"/>
@@ -34596,6 +34595,7 @@
   <int value="10" label="Streamer not ready when GetSource called"/>
   <int value="11" label="Internal script"/>
   <int value="12" label="Streaming was never started"/>
+  <int value="13" label="An error had occurred before GetSource was called"/>
 </enum>
 
 <enum name="NPAPIPluginStatus">
@@ -40306,6 +40306,7 @@
   <int value="9" label="Disabled by config"/>
   <int value="10" label="Path degrading not enabled"/>
   <int value="11" label="Timeout with no new network"/>
+  <int value="12" label="Path degrading before handshake confirmed"/>
 </enum>
 
 <enum name="QuicDisabledReason">
@@ -46184,6 +46185,11 @@
   <int value="1" label="Synced favicons not full"/>
 </enum>
 
+<enum name="SyncFeatureOrTransport">
+  <int value="0" label="Full Sync feature."/>
+  <int value="1" label="Sync transport only."/>
+</enum>
+
 <enum name="SyncFSConflictResolutionPolicy">
   <int value="0" label="Unknown"/>
   <int value="1" label="LastWriteWin"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 37f81557..174af7b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -86532,14 +86532,19 @@
 </histogram>
 
 <histogram name="SBClientDownload.PPAPIDownloadRequest.RequestDuration"
-    units="ms" expires_after="2018-08-30">
+    units="ms">
+  <obsolete>
+    Removed in 08/2018.
+  </obsolete>
   <owner>asanka@chromium.org</owner>
   <summary>Time taken to complete a PPAPIDownloadRequest.</summary>
 </histogram>
 
 <histogram name="SBClientDownload.PPAPIDownloadRequest.RequestOutcome"
-    enum="SBClientDownloadPPAPIDownloadRequestOutcome"
-    expires_after="2018-08-30">
+    enum="SBClientDownloadPPAPIDownloadRequestOutcome">
+  <obsolete>
+    Removed in 08/2018.
+  </obsolete>
   <owner>asanka@chromium.org</owner>
   <summary>
     Outcome of running CheckPPAPIDownloadRequest. Most failure modes cause an
@@ -86551,7 +86556,10 @@
 </histogram>
 
 <histogram name="SBClientDownload.PPAPIDownloadRequest.Result"
-    enum="SBClientDownloadCheckResult" expires_after="2018-08-30">
+    enum="SBClientDownloadCheckResult">
+  <obsolete>
+    Removed in 08/2018.
+  </obsolete>
   <owner>asanka@chromium.org</owner>
   <summary>Result returned to the caller of CheckPPAPIDownloadRequest.</summary>
 </histogram>
@@ -100444,6 +100452,18 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.ConfigureDataTypeManagerOption"
+    enum="SyncFeatureOrTransport">
+  <owner>treib@chromium.org</owner>
+  <summary>
+    Whether the full Sync feature or only the Sync transport layer is being
+    configured. Recorded when configuring the data types for any reason: Most
+    commonly during browser startup, but also after initial setup, after a
+    reconfiguration by the user, or when switching between full feature mode and
+    transport mode.
+  </summary>
+</histogram>
+
 <histogram name="Sync.ConfigureDataTypes" enum="SyncModelTypes">
   <owner>zea@chromium.org</owner>
   <summary>
@@ -101152,8 +101172,8 @@
     wouldn't be able to start, or that it probably can start. The user having
     turned off sync on mobile will be logged as &quot;turned off by user&quot;.
     A dashboard stop and clear will fall under &quot;turned off and setup not
-    completed&quot;. See the SyncInitialState enum in profile_sync_service.h for
-    more information.
+    completed&quot;. See the SyncInitialState enum in profile_sync_service.cc
+    for more information.
   </summary>
 </histogram>
 
@@ -105982,6 +106002,14 @@
   </summary>
 </histogram>
 
+<histogram name="UKM.LogUploader.UploadSize" units="bytes">
+  <owner>asvitkine@chromium.org</owner>
+  <owner>holte@chromium.org</owner>
+  <summary>
+    Reports total upload length in bytes when the UKM service type is used.
+  </summary>
+</histogram>
+
 <histogram name="UKM.PersistentLogRecall.Status"
     enum="PersistedLogsLogReadStatus">
   <owner>holte@chromium.org</owner>
@@ -106675,6 +106703,14 @@
   </summary>
 </histogram>
 
+<histogram name="UMA.LogUploader.UploadSize" units="bytes">
+  <owner>asvitkine@chromium.org</owner>
+  <owner>holte@chromium.org</owner>
+  <summary>
+    Reports total upload length in bytes when the UMA service type is used.
+  </summary>
+</histogram>
+
 <histogram name="UMA.LowEntropySourceValue" expires_after="2018-08-30">
   <owner>asvitkine@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perf_benchmark_unittest.py b/tools/perf/core/perf_benchmark_unittest.py
index 9e81950..e5140255 100644
--- a/tools/perf/core/perf_benchmark_unittest.py
+++ b/tools/perf/core/perf_benchmark_unittest.py
@@ -8,6 +8,7 @@
 import tempfile
 import unittest
 
+from telemetry import decorators
 from telemetry.internal.browser import browser_finder
 from telemetry.testing import options_for_unittests
 
@@ -34,6 +35,7 @@
     self.assertEqual(num_expected_matches, len(ruleset_data_to_copy))
 
 
+  @decorators.Disabled('chromeos')  # crbug.com/871600.
   def testVariationArgs(self):
     benchmark = perf_benchmark.PerfBenchmark()
     options = options_for_unittests.GetCopy()
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 03115809..391405e 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -326,7 +326,7 @@
       'tests': [
         {
           'isolate': 'performance_test_suite',
-          'num_shards': 5,
+          'num_shards': 26,
           'extra_args': [
               '--run-ref-build',
               '--test-shard-map-filename=win10_shard_map.json',
diff --git a/tools/perf/core/shard_maps/timing_data/win10_story_timing.json b/tools/perf/core/shard_maps/timing_data/win10_story_timing.json
index c35cc3a8..43fd7e1 100644
--- a/tools/perf/core/shard_maps/timing_data/win10_story_timing.json
+++ b/tools/perf/core/shard_maps/timing_data/win10_story_timing.json
@@ -1,5662 +1,4090 @@
 [
     {
-        "duration": "19.996899",
+        "duration": "9.0",
         "name": "blink_perf.bindings/append-child.html"
     },
     {
-        "duration": "9.156232333333337",
+        "duration": "9.0",
         "name": "blink_perf.bindings/create-element.html"
     },
     {
-        "duration": "8.43875755959596",
+        "duration": "9.0",
         "name": "blink_perf.bindings/document-implementation.html"
     },
     {
-        "duration": "8.30231310909091",
+        "duration": "9.0",
         "name": "blink_perf.bindings/dom-attribute-on-prototoype.html"
     },
     {
-        "duration": "8.511131287878786",
+        "duration": "9.0",
         "name": "blink_perf.bindings/first-child.html"
     },
     {
-        "duration": "4.966787875757576",
+        "duration": "6.0",
         "name": "blink_perf.bindings/gc-forest.html"
     },
     {
-        "duration": "5.425777770707072",
+        "duration": "6.0",
         "name": "blink_perf.bindings/gc-mini-tree.html"
     },
     {
-        "duration": "13.764999969696973",
+        "duration": "15.0",
         "name": "blink_perf.bindings/gc-tree.html"
     },
     {
-        "duration": "8.376131291919192",
+        "duration": "9.0",
         "name": "blink_perf.bindings/get-attribute-rare.html"
     },
     {
-        "duration": "8.406201976767678",
+        "duration": "9.0",
         "name": "blink_perf.bindings/get-attribute.html"
     },
     {
-        "duration": "8.361707043434341",
+        "duration": "9.0",
         "name": "blink_perf.bindings/get-element-by-id.html"
     },
     {
-        "duration": "8.36879796161616",
+        "duration": "9.0",
         "name": "blink_perf.bindings/get-elements-by-tag-name.html"
     },
     {
-        "duration": "8.370595921212116",
+        "duration": "9.0",
         "name": "blink_perf.bindings/id-getter.html"
     },
     {
-        "duration": "8.392090883838385",
+        "duration": "9.0",
         "name": "blink_perf.bindings/id-setter.html"
     },
     {
-        "duration": "8.37116158282828",
+        "duration": "9.0",
         "name": "blink_perf.bindings/indexed-getter.html"
     },
     {
-        "duration": "8.370979846464643",
+        "duration": "9.0",
         "name": "blink_perf.bindings/insert-before.html"
     },
     {
-        "duration": "8.35701008383838",
+        "duration": "9.0",
         "name": "blink_perf.bindings/named-property-enumerator.html"
     },
     {
-        "duration": "19.448999979797986",
+        "duration": "29.0",
         "name": "blink_perf.bindings/node-list-access.html"
     },
     {
-        "duration": "8.215616140404043",
+        "duration": "9.0",
         "name": "blink_perf.bindings/node-type.html"
     },
     {
-        "duration": "3.2637171666666673",
+        "duration": "4.0",
         "name": "blink_perf.bindings/post-message.html"
     },
     {
-        "duration": "8.835181823232325",
+        "duration": "9.0",
         "name": "blink_perf.bindings/sequence-conversion-array.html"
     },
     {
-        "duration": "10.57738384343434",
+        "duration": "11.0",
         "name": "blink_perf.bindings/sequence-conversion-custom-iterator.html"
     },
     {
-        "duration": "3.319979792929293",
+        "duration": "4.0",
         "name": "blink_perf.bindings/serialize-array.html"
     },
     {
-        "duration": "3.145494944444445",
+        "duration": "4.0",
         "name": "blink_perf.bindings/serialize-long-string.html"
     },
     {
-        "duration": "4.366848494949494",
+        "duration": "5.0",
         "name": "blink_perf.bindings/serialize-map.html"
     },
     {
-        "duration": "3.8737272787878783",
+        "duration": "4.0",
         "name": "blink_perf.bindings/serialize-nested-array.html"
     },
     {
-        "duration": "9.2633434989899",
+        "duration": "9.0",
         "name": "blink_perf.bindings/set-attribute-rare.html"
     },
     {
-        "duration": "8.423212149494947",
+        "duration": "9.0",
         "name": "blink_perf.bindings/set-attribute.html"
     },
     {
-        "duration": "7.112868693939398",
+        "duration": "8.0",
         "name": "blink_perf.bindings/structured-clone-json-deserialize.html"
     },
     {
-        "duration": "7.0847777656565665",
+        "duration": "8.0",
         "name": "blink_perf.bindings/structured-clone-json-serialize.html"
     },
     {
-        "duration": "4.828333351515152",
+        "duration": "5.0",
         "name": "blink_perf.bindings/structured-clone-long-string-deserialize.html"
     },
     {
-        "duration": "4.825535373737372",
+        "duration": "5.0",
         "name": "blink_perf.bindings/structured-clone-long-string-serialize.html"
     },
     {
-        "duration": "8.398313140404037",
+        "duration": "10.0",
         "name": "blink_perf.bindings/typed-array-construct-from-array.html"
     },
     {
-        "duration": "8.286191913131317",
+        "duration": "9.0",
         "name": "blink_perf.bindings/typed-array-construct-from-same-type.html"
     },
     {
-        "duration": "8.383909067676763",
+        "duration": "9.0",
         "name": "blink_perf.bindings/typed-array-construct-from-typed.html"
     },
     {
-        "duration": "8.382272715151514",
+        "duration": "9.0",
         "name": "blink_perf.bindings/typed-array-set-from-typed.html"
     },
     {
-        "duration": "8.291282852525253",
+        "duration": "9.0",
         "name": "blink_perf.bindings/undefined-first-child.html"
     },
     {
-        "duration": "8.195070692929294",
+        "duration": "9.0",
         "name": "blink_perf.bindings/undefined-get-element-by-id.html"
     },
     {
-        "duration": "8.380313166666667",
+        "duration": "9.0",
         "name": "blink_perf.bindings/undefined-id-getter.html"
     },
     {
-        "duration": "17.35878788383838",
+        "duration": "13.0",
+        "name": "blink_perf.bindings/worker-structured-clone-json-roundtrip.html"
+    },
+    {
+        "duration": "13.0",
+        "name": "blink_perf.bindings/worker-structured-clone-json-serialize.html"
+    },
+    {
+        "duration": "9.0",
         "name": "blink_perf.canvas/createImageBitmapFromImageData.html"
     },
     {
-        "duration": "5.463151526262625",
+        "duration": "6.0",
         "name": "blink_perf.canvas/draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html"
     },
     {
-        "duration": "9.78419193939394",
+        "duration": "10.0",
         "name": "blink_perf.canvas/draw-dynamic-webgl-to-hw-accelerated-canvas-2d.html"
     },
     {
-        "duration": "3.3580100989898996",
+        "duration": "4.0",
         "name": "blink_perf.canvas/draw-hw-accelerated-canvas-2d-to-sw-canvas-2d.html"
     },
     {
-        "duration": "4.187777782828281",
+        "duration": "5.0",
         "name": "blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html"
     },
     {
-        "duration": "4.316737364646463",
+        "duration": "5.0",
         "name": "blink_perf.canvas/draw-static-webgl-to-hw-accelerated-canvas-2d.html"
     },
     {
-        "duration": "5.465969692929293",
+        "duration": "6.0",
         "name": "blink_perf.canvas/draw-video-to-hw-accelerated-canvas-2d.html"
     },
     {
-        "duration": "9.203727292929292",
+        "duration": "10.0",
         "name": "blink_perf.canvas/drawimage-not-pixelaligned.html"
     },
     {
-        "duration": "8.625272782828286",
+        "duration": "9.0",
         "name": "blink_perf.canvas/drawimage.html"
     },
     {
-        "duration": "8.994323237373736",
+        "duration": "10.0",
         "name": "blink_perf.canvas/getImageData.html"
     },
     {
-        "duration": "9.997010131313134",
+        "duration": "9.0",
         "name": "blink_perf.canvas/getImageDataColorManaged.html"
     },
     {
-        "duration": "8.6022726969697",
+        "duration": "9.0",
         "name": "blink_perf.canvas/putImageData.html"
     },
     {
-        "duration": "4.57739395959596",
+        "duration": "5.0",
         "name": "blink_perf.canvas/toBlob_duration.html"
     },
     {
-        "duration": "4.4193939434343426",
+        "duration": "5.0",
         "name": "blink_perf.canvas/toBlob_duration_jpeg.html"
     },
     {
-        "duration": "3.9589596020202023",
+        "duration": "5.0",
         "name": "blink_perf.canvas/transferFromImageBitmap.html"
     },
     {
-        "duration": "4.83388886161616",
+        "duration": "6.0",
         "name": "blink_perf.canvas/upload-canvas-2d-to-texture.html"
     },
     {
-        "duration": "10.408202035353534",
+        "duration": "11.0",
         "name": "blink_perf.canvas/upload-video-to-sub-texture.html"
     },
     {
-        "duration": "4.488111119191919",
+        "duration": "5.0",
         "name": "blink_perf.canvas/upload-video-to-texture.html"
     },
     {
-        "duration": "4.474373743434344",
+        "duration": "5.0",
         "name": "blink_perf.canvas/upload-webgl-to-texture.html"
     },
     {
-        "duration": "22.907646414141407",
+        "duration": "16.0",
         "name": "blink_perf.css/AttributeDescendantSelector.html"
     },
     {
-        "duration": "8.595363611111113",
+        "duration": "9.0",
         "name": "blink_perf.css/CSSPropertySetterGetter.html"
     },
     {
-        "duration": "8.476989914141416",
+        "duration": "9.0",
         "name": "blink_perf.css/CSSPropertySetterGetterMethods.html"
     },
     {
-        "duration": "8.610393959595962",
+        "duration": "9.0",
         "name": "blink_perf.css/CSSPropertyUpdateValue.html"
     },
     {
-        "duration": "7.437707064646462",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleChildClassSelector.html"
     },
     {
-        "duration": "7.415909092929293",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleChildElementSelectors.html"
     },
     {
-        "duration": "7.398494929292931",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleElementSelector.html"
     },
     {
-        "duration": "7.389262617171715",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleGrandChildElementSelector.html"
     },
     {
-        "duration": "7.380636365656567",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleMultipleClassSelector.html"
     },
     {
-        "duration": "7.376888870707073",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleMultipleQualifiedDataAttributesWithValuesSelector.html"
     },
     {
-        "duration": "7.392999971717171",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleNestedPseudoSelector.html"
     },
     {
-        "duration": "7.377353527272726",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStylePairOfNthChildSelector.html"
     },
     {
-        "duration": "7.329000001010102",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStylePartialAttributeMatchingSelector.html"
     },
     {
-        "duration": "7.402767671717169",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeSelector.html"
     },
     {
-        "duration": "7.3826363515151545",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeWithValueSelector.html"
     },
     {
-        "duration": "8.161272755555558",
+        "duration": "9.0",
         "name": "blink_perf.css/ChangeStyleShallowTree.html"
     },
     {
-        "duration": "7.332252533333335",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleSingleClassSelector.html"
     },
     {
-        "duration": "7.333636354545453",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleSingleNthChildSelector.html"
     },
     {
-        "duration": "7.334646465656564",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleSinglePseudoSelector.html"
     },
     {
-        "duration": "7.352949464646463",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleUniversalSelector.html"
     },
     {
-        "duration": "7.337292902020198",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeSelector.html"
     },
     {
-        "duration": "7.345141414141416",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeWithValueSelector.html"
     },
     {
-        "duration": "11.310242439393942",
+        "duration": "12.0",
         "name": "blink_perf.css/ClassDescendantSelector.html"
     },
     {
-        "duration": "8.640323222222223",
+        "duration": "9.0",
         "name": "blink_perf.css/ClassInvalidation.html"
     },
     {
-        "duration": "10.3898888989899",
+        "duration": "11.0",
         "name": "blink_perf.css/FocusUpdate.html"
     },
     {
-        "duration": "7.606757575757573",
+        "duration": "8.0",
         "name": "blink_perf.css/LoadBootstrapBlog.html"
     },
     {
-        "duration": "7.589444408080805",
+        "duration": "8.0",
         "name": "blink_perf.css/LoadMaterializeStarterPage.html"
     },
     {
-        "duration": "7.826080848484851",
+        "duration": "8.0",
         "name": "blink_perf.css/LoadSemanticPageExample.html"
     },
     {
-        "duration": "8.388262628282828",
+        "duration": "9.0",
         "name": "blink_perf.css/PseudoClassSelectors.html"
     },
     {
-        "duration": "8.893141429292932",
+        "duration": "9.0",
         "name": "blink_perf.css/SelectorCountScaling.html"
     },
     {
-        "duration": "17.572676757575756",
+        "duration": "6.0",
         "name": "blink_perf.dom/addRange.html"
     },
     {
-        "duration": "3.935171708080808",
+        "duration": "4.0",
         "name": "blink_perf.dom/delete-in-password-field.html"
     },
     {
-        "duration": "9.663727282828281",
+        "duration": "10.0",
         "name": "blink_perf.dom/div-editable.html"
     },
     {
-        "duration": "3.364191908080807",
+        "duration": "4.0",
         "name": "blink_perf.dom/inner_html_with_selection.html"
     },
     {
-        "duration": "14.697616196969697",
+        "duration": "19.0",
         "name": "blink_perf.dom/long-sibling-list.html"
     },
     {
-        "duration": "4.027606073737373",
+        "duration": "5.0",
         "name": "blink_perf.dom/modify-element-classname.html"
     },
     {
-        "duration": "3.6468585707070718",
+        "duration": "4.0",
         "name": "blink_perf.dom/modify-element-id.html"
     },
     {
-        "duration": "3.698080822222223",
+        "duration": "4.0",
         "name": "blink_perf.dom/modify-element-title.html"
     },
     {
-        "duration": "3.652434341414141",
+        "duration": "4.0",
         "name": "blink_perf.dom/move-down-with-hidden-elements.html"
     },
     {
-        "duration": "3.544151515151514",
+        "duration": "5.0",
         "name": "blink_perf.dom/move-up-with-hidden-elements.html"
     },
     {
-        "duration": "3.617484854545455",
+        "duration": "4.0",
         "name": "blink_perf.dom/remove_child_with_selection.html"
     },
     {
-        "duration": "8.782686893939388",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-multiple-add.html"
     },
     {
-        "duration": "8.637939409090908",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-single-add.html"
     },
     {
-        "duration": "8.717414171717175",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-single-remove.html"
     },
     {
-        "duration": "8.921020191919192",
+        "duration": "9.0",
         "name": "blink_perf.dom/textarea-dom.html"
     },
     {
-        "duration": "8.796272751515147",
+        "duration": "9.0",
         "name": "blink_perf.dom/textarea-edit.html"
     },
     {
-        "duration": "16.206686873737382",
+        "duration": "17.0",
         "name": "blink_perf.events/EventsDispatching.html"
     },
     {
-        "duration": "9.35467675757576",
+        "duration": "10.0",
         "name": "blink_perf.events/EventsDispatchingInDeeplyNestedShadowTrees.html"
     },
     {
-        "duration": "12.775090868686865",
+        "duration": "16.0",
         "name": "blink_perf.events/EventsDispatchingInShadowTrees.html"
     },
     {
-        "duration": "8.086616182828283",
+        "duration": "11.0",
         "name": "blink_perf.events/hit-test-lots-of-layers.html"
     },
     {
-        "duration": "65.56014138383837",
+        "duration": "15.0",
         "name": "blink_perf.image_decoder/decode-gif.html"
     },
     {
-        "duration": "9.819111131313132",
+        "duration": "10.0",
         "name": "blink_perf.image_decoder/decode-jpeg.html"
     },
     {
-        "duration": "13.537434308080812",
+        "duration": "13.0",
         "name": "blink_perf.image_decoder/decode-lossless-webp.html"
     },
     {
-        "duration": "9.061585903030302",
+        "duration": "9.0",
         "name": "blink_perf.image_decoder/decode-lossy-webp.html"
     },
     {
-        "duration": "10.58182828282828",
+        "duration": "10.0",
         "name": "blink_perf.image_decoder/decode-png-palette-opaque.html"
     },
     {
-        "duration": "9.544272696969697",
+        "duration": "9.0",
         "name": "blink_perf.image_decoder/decode-png-palette.html"
     },
     {
-        "duration": "12.752656585858585",
+        "duration": "13.0",
         "name": "blink_perf.image_decoder/decode-png.html"
     },
     {
-        "duration": "18.947606092929295",
+        "duration": "12.0",
         "name": "blink_perf.layout/ArabicLineLayout.html"
     },
     {
-        "duration": "3.509444423232323",
+        "duration": "4.0",
         "name": "blink_perf.layout/Shapes/MultipleShapes.html"
     },
     {
-        "duration": "8.547484808080808",
+        "duration": "9.0",
         "name": "blink_perf.layout/SimpleTextPathLineLayout.html"
     },
     {
-        "duration": "11.027383853535351",
+        "duration": "9.0",
         "name": "blink_perf.layout/add-remove-inline-floats.html"
     },
     {
-        "duration": "8.954101007070706",
+        "duration": "9.0",
         "name": "blink_perf.layout/attach-inlines-2.html"
     },
     {
-        "duration": "8.298616216161616",
+        "duration": "9.0",
         "name": "blink_perf.layout/attach-inlines.html"
     },
     {
-        "duration": "9.218161585858589",
+        "duration": "9.0",
         "name": "blink_perf.layout/auto-grid-lots-of-data.html"
     },
     {
-        "duration": "9.579525222222223",
+        "duration": "11.0",
+        "name": "blink_perf.layout/change-text-css-contain.html"
+    },
+    {
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-once-random.html"
     },
     {
-        "duration": "8.9726465",
+        "duration": "10.0",
         "name": "blink_perf.layout/chapter-reflow-once.html"
     },
     {
-        "duration": "8.197999997979798",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-thrice.html"
     },
     {
-        "duration": "8.205798000000003",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-twice.html"
     },
     {
-        "duration": "8.074090939393937",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow.html"
     },
     {
-        "duration": "5.536888917171718",
+        "duration": "7.0",
         "name": "blink_perf.layout/character_fallback.html"
     },
     {
-        "duration": "3.261747474747475",
+        "duration": "4.0",
         "name": "blink_perf.layout/character_fallback_aat.html"
     },
     {
-        "duration": "9.281595989898989",
+        "duration": "9.0",
         "name": "blink_perf.layout/fixed-grid-lots-of-data.html"
     },
     {
-        "duration": "9.146888848484847",
+        "duration": "9.0",
         "name": "blink_perf.layout/fixed-grid-lots-of-stretched-data.html"
     },
     {
-        "duration": "8.400161631313136",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-column-nowrap.html"
     },
     {
-        "duration": "8.462201997979799",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-column-wrap.html"
     },
     {
-        "duration": "8.362212107070707",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-deeply-nested-column-flow.html"
     },
     {
-        "duration": "8.58810097979798",
+        "duration": "10.0",
         "name": "blink_perf.layout/flexbox-lots-of-data.html"
     },
     {
-        "duration": "8.248353522222226",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-row-nowrap.html"
     },
     {
-        "duration": "8.221979809090909",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-row-wrap.html"
     },
     {
-        "duration": "9.274141398989899",
+        "duration": "10.0",
         "name": "blink_perf.layout/flexbox-with-stretch-layout.html"
     },
     {
-        "duration": "7.264454541414142",
+        "duration": "8.0",
         "name": "blink_perf.layout/floats_100_100.html"
     },
     {
-        "duration": "7.287424223232322",
+        "duration": "8.0",
         "name": "blink_perf.layout/floats_100_100_nested.html"
     },
     {
-        "duration": "5.380808066666666",
+        "duration": "6.0",
         "name": "blink_perf.layout/floats_10_1000.html"
     },
     {
-        "duration": "4.327999992929294",
+        "duration": "5.0",
         "name": "blink_perf.layout/floats_20_100.html"
     },
     {
-        "duration": "4.65909091111111",
+        "duration": "5.0",
         "name": "blink_perf.layout/floats_20_100_nested.html"
     },
     {
-        "duration": "3.805828268686869",
+        "duration": "5.0",
         "name": "blink_perf.layout/floats_2_100.html"
     },
     {
-        "duration": "3.869171721212122",
+        "duration": "4.0",
         "name": "blink_perf.layout/floats_2_100_nested.html"
     },
     {
-        "duration": "4.985525238383841",
+        "duration": "5.0",
         "name": "blink_perf.layout/floats_50_100.html"
     },
     {
-        "duration": "5.068727260606062",
+        "duration": "6.0",
         "name": "blink_perf.layout/floats_50_100_nested.html"
     },
     {
-        "duration": "8.537181798989899",
+        "duration": "9.0",
         "name": "blink_perf.layout/hindi-line-layout.html"
     },
     {
-        "duration": "7.121080791919193",
+        "duration": "9.0",
+        "name": "blink_perf.layout/large-spanning-grid-item.html"
+    },
+    {
+        "duration": "8.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans-wider-than-table.html"
     },
     {
-        "duration": "7.105181829292929",
+        "duration": "8.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans.html"
     },
     {
-        "duration": "7.045474754545456",
+        "duration": "8.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-no-colspans.html"
     },
     {
-        "duration": "3.346484848484849",
-        "name": "blink_perf.layout/latin-complex-text.html"
+        "duration": "42.0",
+        "name": "blink_perf.layout/latin-ebook-resize.html"
     },
     {
-        "duration": "3.6330707060606056",
+        "duration": "12.0",
+        "name": "blink_perf.layout/latin-ebook.html"
+    },
+    {
+        "duration": "4.0",
         "name": "blink_perf.layout/layers_overlap_2d.html"
     },
     {
-        "duration": "3.752888907070708",
+        "duration": "4.0",
         "name": "blink_perf.layout/layers_overlap_3d.html"
     },
     {
-        "duration": "7.253565652525253",
+        "duration": "8.0",
         "name": "blink_perf.layout/line-layout-line-height.html"
     },
     {
-        "duration": "8.558373762626262",
+        "duration": "9.0",
         "name": "blink_perf.layout/line-layout-repeat-append.html"
     },
     {
-        "duration": "8.186737343434345",
+        "duration": "9.0",
         "name": "blink_perf.layout/line-layout.html"
     },
     {
-        "duration": "3.327555552525252",
+        "duration": "4.0",
         "name": "blink_perf.layout/long-line-nowrap-collapse.html"
     },
     {
-        "duration": "3.3382929383838387",
+        "duration": "4.0",
         "name": "blink_perf.layout/long-line-nowrap-spans-collapse.html"
     },
     {
-        "duration": "4.858424242424244",
+        "duration": "5.0",
         "name": "blink_perf.layout/long-line-nowrap.html"
     },
     {
-        "duration": "9.10998988383838",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/deeply-nested-tables.html"
     },
     {
-        "duration": "8.83554547070707",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/fixed-height-with-spanner-and-nested-tables.html"
     },
     {
-        "duration": "8.304888890909089",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/lots-of-text-autofill.html"
     },
     {
-        "duration": "8.313949487878789",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/lots-of-text-balanced-orphans-widows.html"
     },
     {
-        "duration": "8.073010090909087",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/lots-of-text-balanced.html"
     },
     {
-        "duration": "8.377909106060606",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/tall-content-short-columns-realistic.html"
     },
     {
-        "duration": "8.295161604040402",
+        "duration": "9.0",
         "name": "blink_perf.layout/multicol/tall-content-short-columns.html"
     },
     {
-        "duration": "8.375201976767677",
+        "duration": "9.0",
         "name": "blink_perf.layout/nested-blocks-with-percent-height-and-max-height.html"
     },
     {
-        "duration": "8.208010116161617",
+        "duration": "9.0",
         "name": "blink_perf.layout/nested-grid.html"
     },
     {
-        "duration": "8.243555550505057",
+        "duration": "9.0",
         "name": "blink_perf.layout/nested-percent-height-tables.html"
     },
     {
-        "duration": "32.9910606060606",
+        "duration": "34.0",
         "name": "blink_perf.layout/subtree-detaching.html"
     },
     {
-        "duration": "3.89325253030303",
+        "duration": "4.0",
         "name": "blink_perf.layout/vertical-japanese-kokoro-insert.html"
     },
     {
-        "duration": "4.3011010040404045",
+        "duration": "5.0",
         "name": "blink_perf.layout/word-break-break-all.html"
     },
     {
-        "duration": "4.459707066666663",
+        "duration": "5.0",
         "name": "blink_perf.layout/word-break-break-word.html"
     },
     {
-        "duration": "4.607626281818178",
+        "duration": "5.0",
         "name": "blink_perf.layout/word-wrap-break-word.html"
     },
     {
-        "duration": "32.56997982828283",
+        "duration": "20.0",
         "name": "blink_perf.owp_storage/blob-perf-files.html"
     },
     {
-        "duration": "9.272777772727274",
+        "duration": "9.0",
         "name": "blink_perf.owp_storage/blob-perf-ipc.html"
     },
     {
-        "duration": "8.302111108080808",
+        "duration": "9.0",
         "name": "blink_perf.owp_storage/blob-perf-shm.html"
     },
     {
-        "duration": "9.117333297979796",
+        "duration": "10.0",
         "name": "blink_perf.owp_storage/blob-perf-tiny.html"
     },
     {
-        "duration": "13.110434323232322",
+        "duration": "13.0",
         "name": "blink_perf.owp_storage/idb-load-docs.html"
     },
     {
-        "duration": "16.175020202020203",
+        "duration": "9.0",
         "name": "blink_perf.paint/appending-text.html"
     },
     {
-        "duration": "12.853030308080807",
+        "duration": "13.0",
         "name": "blink_perf.paint/color-changes.html"
     },
     {
-        "duration": "12.522818196969695",
+        "duration": "13.0",
         "name": "blink_perf.paint/complex-content-slow-scroll.html"
     },
     {
-        "duration": "10.464747479797984",
+        "duration": "11.0",
         "name": "blink_perf.paint/containment-resize.html"
     },
     {
-        "duration": "10.300272747474747",
+        "duration": "11.0",
         "name": "blink_perf.paint/fixed-and-many-layers-scroll.html"
     },
     {
-        "duration": "11.4118888989899",
+        "duration": "12.0",
         "name": "blink_perf.paint/large-table-background-change-with-invisible-collapsed-borders.html"
     },
     {
-        "duration": "9.514404085858587",
+        "duration": "10.0",
         "name": "blink_perf.paint/large-table-background-change-with-visible-collapsed-borders.html"
     },
     {
-        "duration": "11.730878752525253",
+        "duration": "12.0",
         "name": "blink_perf.paint/large-table-background-change-with-zero-width-collapsed-borders.html"
     },
     {
-        "duration": "9.963010126262631",
+        "duration": "11.0",
         "name": "blink_perf.paint/large-table-collapsed-border-change-with-backgrounds.html"
     },
     {
-        "duration": "10.524818131313129",
+        "duration": "11.0",
         "name": "blink_perf.paint/large-table-collapsed-border-change-with-text.html"
     },
     {
-        "duration": "8.973393934343438",
+        "duration": "9.0",
         "name": "blink_perf.paint/large-table-collapsed-border-change.html"
     },
     {
-        "duration": "10.428828242424247",
+        "duration": "11.0",
         "name": "blink_perf.paint/large-table-repaint.html"
     },
     {
-        "duration": "8.833666651515154",
+        "duration": "9.0",
         "name": "blink_perf.paint/move-text-with-mask.html"
     },
     {
-        "duration": "10.244737388888883",
+        "duration": "11.0",
         "name": "blink_perf.paint/paint-offset-changes.html"
     },
     {
-        "duration": "13.593020191919194",
+        "duration": "18.0",
         "name": "blink_perf.paint/transform-changes.html"
     },
     {
-        "duration": "18.802565686868693",
+        "duration": "12.0",
         "name": "blink_perf.parser/css-parser-yui.html"
     },
     {
-        "duration": "7.583060596969697",
+        "duration": "8.0",
         "name": "blink_perf.parser/html-parser-threaded.html"
     },
     {
-        "duration": "7.217404042424242",
+        "duration": "8.0",
         "name": "blink_perf.parser/html-parser.html"
     },
     {
-        "duration": "21.312282767676773",
+        "duration": "21.0",
         "name": "blink_perf.parser/html5-full-render.html"
     },
     {
-        "duration": "9.200919196969691",
+        "duration": "10.0",
         "name": "blink_perf.parser/iframe-append-remove.html"
     },
     {
-        "duration": "8.843555555555556",
+        "duration": "9.0",
         "name": "blink_perf.parser/innerHTML-setter-siblings.html"
     },
     {
-        "duration": "8.766969702020198",
+        "duration": "9.0",
         "name": "blink_perf.parser/innerHTML-setter.html"
     },
     {
-        "duration": "8.663414116161618",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-attribute-complex.html"
     },
     {
-        "duration": "8.576505040404038",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-attribute.html"
     },
     {
-        "duration": "8.474474765656568",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-class-deep.html"
     },
     {
-        "duration": "9.299161575757577",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-class-first.html"
     },
     {
-        "duration": "8.414717176767676",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-class-last.html"
     },
     {
-        "duration": "8.55489894848485",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-class.html"
     },
     {
-        "duration": "8.514272675757574",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-deep.html"
     },
     {
-        "duration": "9.268101030303031",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-first.html"
     },
     {
-        "duration": "9.338040449494953",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-id-deep.html"
     },
     {
-        "duration": "9.265838373737374",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-id-first.html"
     },
     {
-        "duration": "9.477414116161622",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-id-last.html"
     },
     {
-        "duration": "8.46759596969697",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-last.html"
     },
     {
-        "duration": "8.296292951515149",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-deep.html"
     },
     {
-        "duration": "8.269939439393939",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-first.html"
     },
     {
-        "duration": "8.322747490909089",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-id-deep.html"
     },
     {
-        "duration": "8.530777778787877",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-id-last.html"
     },
     {
-        "duration": "8.417727281818184",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-last.html"
     },
     {
-        "duration": "8.109979769696968",
+        "duration": "9.0",
         "name": "blink_perf.parser/simple-url.html"
     },
     {
-        "duration": "8.719798020202017",
+        "duration": "9.0",
         "name": "blink_perf.parser/textarea-parsing.html"
     },
     {
-        "duration": "8.91624238888889",
+        "duration": "9.0",
         "name": "blink_perf.parser/tiny-innerHTML.html"
     },
     {
-        "duration": "9.241100984848485",
+        "duration": "10.0",
         "name": "blink_perf.parser/url-parser.html"
     },
     {
-        "duration": "7.880505068686869",
+        "duration": "9.0",
         "name": "blink_perf.parser/xml-parser.html"
     },
     {
-        "duration": "12.34037373838384",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/shadow-style-share-attr-selectors.html"
     },
     {
-        "duration": "4.270252529292932",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/shadow-style-share-media-query.html"
     },
     {
-        "duration": "4.241000009090909",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/shadow-style-share-with-distribution.html"
     },
     {
-        "duration": "4.8917171757575755",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/shadow-style-share.html"
     },
     {
-        "duration": "4.796333336363637",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/style-sheet-insert.html"
     },
     {
-        "duration": "3.6853737434343428",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-changing-classname-with-shadow-dom.html"
     },
     {
-        "duration": "3.764878785858585",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-changing-classname-without-shadow-dom.html"
     },
     {
-        "duration": "4.745979779797979",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v0-changing-select-with-shadow-dom.html"
     },
     {
-        "duration": "5.141030298989901",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v0-changing-select-without-shadow-dom.html"
     },
     {
-        "duration": "3.947484861616161",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-content-reprojection.html"
     },
     {
-        "duration": "3.6637878797979817",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-large-distribution-without-layout.html"
     },
     {
-        "duration": "3.6803737383838393",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-multiple-insertion-points.html"
     },
     {
-        "duration": "3.9176767656565654",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-shadow-reprojection.html"
     },
     {
-        "duration": "4.389949510101011",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v0-small-distribution-with-layout.html"
     },
     {
-        "duration": "12.176565601010097",
+        "duration": "11.0",
         "name": "blink_perf.shadow_dom/v1-distribution-disconnected-and-reconnected.html"
     },
     {
-        "duration": "3.3039191898989895",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-distribution.html"
     },
     {
-        "duration": "3.3323939343434335",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-host-child-append.html"
     },
     {
-        "duration": "11.572313095959593",
+        "duration": "11.0",
         "name": "blink_perf.shadow_dom/v1-large-deep-distribution.html"
     },
     {
-        "duration": "20.463808090909094",
+        "duration": "19.0",
         "name": "blink_perf.shadow_dom/v1-large-deep-layout.html"
     },
     {
-        "duration": "3.2629191868686855",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-large-shallow-distribution.html"
     },
     {
-        "duration": "3.305262635353534",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-large-shallow-layout.html"
     },
     {
-        "duration": "3.6749494919191936",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-re-layout.html"
     },
     {
-        "duration": "4.031222225252525",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-slot-assigned-nodes.html"
     },
     {
-        "duration": "3.9982626252525235",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-mutate-deep-tree-then-slot-flatten.html"
     },
     {
-        "duration": "3.6141312919191932",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-re-layout.html"
     },
     {
-        "duration": "3.3712222191919192",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-slot-assigned-nodes.html"
     },
     {
-        "duration": "3.6590605939393925",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-mutate-shallow-tree-then-slot-flatten.html"
     },
     {
-        "duration": "4.0200605959595945",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v1-slot-append.html"
     },
     {
-        "duration": "4.957868676767677",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v1-small-deep-distribution.html"
     },
     {
-        "duration": "4.538727265656566",
+        "duration": "5.0",
         "name": "blink_perf.shadow_dom/v1-small-deep-layout.html"
     },
     {
-        "duration": "3.4889697050505046",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-small-shallow-distribution.html"
     },
     {
-        "duration": "3.5975454494949495",
+        "duration": "4.0",
         "name": "blink_perf.shadow_dom/v1-small-shallow-layout.html"
     },
     {
-        "duration": "11.494909038383836",
+        "duration": "4.0",
         "name": "blink_perf.svg/AzLizardBenjiPark.html"
     },
     {
-        "duration": "4.6980404",
+        "duration": "4.0",
         "name": "blink_perf.svg/Bamboo.html"
     },
     {
-        "duration": "4.092404045454544",
+        "duration": "4.0",
         "name": "blink_perf.svg/Cactus.html"
     },
     {
-        "duration": "4.094000000000001",
+        "duration": "4.0",
         "name": "blink_perf.svg/Cowboy.html"
     },
     {
-        "duration": "5.061656557575756",
-        "name": "blink_perf.svg/Cowboy_transform.html"
-    },
-    {
-        "duration": "3.5484646515151526",
+        "duration": "4.0",
         "name": "blink_perf.svg/CrawFishGanson.html"
     },
     {
-        "duration": "3.5005454444444446",
+        "duration": "4.0",
         "name": "blink_perf.svg/Debian.html"
     },
     {
-        "duration": "3.4699696919191907",
+        "duration": "4.0",
         "name": "blink_perf.svg/DropsOnABlade.html"
     },
     {
-        "duration": "3.81215153131313",
+        "duration": "4.0",
         "name": "blink_perf.svg/FlowerFromMyGarden.html"
     },
     {
-        "duration": "4.067505039393939",
+        "duration": "4.0",
         "name": "blink_perf.svg/FoodLeifLodahl.html"
     },
     {
-        "duration": "3.9484242545454546",
+        "duration": "4.0",
         "name": "blink_perf.svg/France.html"
     },
     {
-        "duration": "3.616010100000001",
+        "duration": "4.0",
         "name": "blink_perf.svg/FrancoBolloGnomeEzechi.html"
     },
     {
-        "duration": "3.8947171717171725",
+        "duration": "4.0",
         "name": "blink_perf.svg/GearFlowers.html"
     },
     {
-        "duration": "4.045040398989902",
+        "duration": "4.0",
         "name": "blink_perf.svg/HarveyRayner.html"
     },
     {
-        "duration": "4.13256565050505",
+        "duration": "4.0",
         "name": "blink_perf.svg/HereGear.html"
     },
     {
-        "duration": "4.843080801010103",
+        "duration": "5.0",
         "name": "blink_perf.svg/MtSaintHelens.html"
     },
     {
-        "duration": "3.4929293050505046",
+        "duration": "4.0",
         "name": "blink_perf.svg/Samurai.html"
     },
     {
-        "duration": "23.492767656565654",
+        "duration": "27.0",
         "name": "blink_perf.svg/SierpinskiCarpet.html"
     },
     {
-        "duration": "3.878919172727274",
+        "duration": "4.0",
         "name": "blink_perf.svg/SvgCubics.html"
     },
     {
-        "duration": "3.6388484787878794",
+        "duration": "4.0",
         "name": "blink_perf.svg/SvgHitTesting.html"
     },
     {
-        "duration": "9.364565661616163",
+        "duration": "9.0",
         "name": "blink_perf.svg/SvgNestedUse.html"
     },
     {
-        "duration": "3.458737377777778",
+        "duration": "4.0",
         "name": "blink_perf.svg/UnderTheSee.html"
     },
     {
-        "duration": "3.574141404040404",
+        "duration": "4.0",
         "name": "blink_perf.svg/WorldIso.html"
     },
     {
-        "duration": "4.211555554545455",
+        "duration": "5.0",
         "name": "blink_perf.svg/Worldcup.html"
     },
     {
-        "duration": "41.77264644444443",
+        "duration": "42.0",
         "name": "dromaeo/http://dromaeo.com?dom-attr"
     },
     {
-        "duration": "33.883939313131314",
+        "duration": "34.0",
         "name": "dromaeo/http://dromaeo.com?dom-modify"
     },
     {
-        "duration": "48.964242363636345",
+        "duration": "49.0",
         "name": "dromaeo/http://dromaeo.com?dom-query"
     },
     {
-        "duration": "30.013323232323227",
+        "duration": "30.0",
         "name": "dromaeo/http://dromaeo.com?dom-traverse"
     },
     {
-        "duration": "22.23553537878789",
-        "name": "dummy_benchmark.histogram_benchmark_1/dummy_page.html"
-    },
-    {
-        "duration": "16.528737389898993",
+        "duration": "3.0",
         "name": "dummy_benchmark.noisy_benchmark_1/dummy_page.html"
     },
     {
-        "duration": "10.877414132323226",
-        "name": "dummy_benchmark.stable_benchmark_1/dummy_page.html"
-    },
-    {
-        "duration": "178.4075252525252",
+        "duration": "178.0",
         "name": "jetstream/http://browserbench.org/JetStream/"
     },
     {
-        "duration": "29.704030292929282",
+        "duration": "20.0",
         "name": "kraken/http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html"
     },
     {
-        "duration": "78.57620210101011",
-        "name": "loading.desktop/24h"
-    },
-    {
-        "duration": "34.89154563636364",
+        "duration": "18.0",
         "name": "loading.desktop/24h_cold"
     },
     {
-        "duration": "42.348090909090914",
+        "duration": "22.0",
         "name": "loading.desktop/24h_warm"
     },
     {
-        "duration": "0.00150001045",
-        "name": "loading.desktop/2ch"
-    },
-    {
-        "duration": "110.41564648484851",
-        "name": "loading.desktop/AirBnB"
-    },
-    {
-        "duration": "44.22172736363637",
+        "duration": "23.0",
         "name": "loading.desktop/AirBnB_cold"
     },
     {
-        "duration": "62.84945436363635",
+        "duration": "32.0",
         "name": "loading.desktop/AirBnB_warm"
     },
     {
-        "duration": "59.46995958585859",
-        "name": "loading.desktop/Aljayyash"
-    },
-    {
-        "duration": "27.844090727272725",
+        "duration": "21.0",
         "name": "loading.desktop/Aljayyash_cold"
     },
     {
-        "duration": "31.365636636363636",
+        "duration": "16.0",
         "name": "loading.desktop/Aljayyash_warm"
     },
     {
-        "duration": "126.35130305050508",
-        "name": "loading.desktop/AllRecipes"
-    },
-    {
-        "duration": "51.872454545454545",
+        "duration": "27.0",
         "name": "loading.desktop/AllRecipes_cold"
     },
     {
-        "duration": "73.06945454545453",
+        "duration": "37.0",
         "name": "loading.desktop/AllRecipes_warm"
     },
     {
-        "duration": "118.84544441414144",
-        "name": "loading.desktop/ArsTechnica"
-    },
-    {
-        "duration": "46.56990909090909",
+        "duration": "23.0",
         "name": "loading.desktop/ArsTechnica_cold"
     },
     {
-        "duration": "70.74781818181818",
+        "duration": "35.0",
         "name": "loading.desktop/ArsTechnica_warm"
     },
     {
-        "duration": "61.44041423232327",
-        "name": "loading.desktop/Baidu"
-    },
-    {
-        "duration": "28.274181909090906",
+        "duration": "14.0",
         "name": "loading.desktop/Baidu_cold"
     },
     {
-        "duration": "31.373181954545455",
+        "duration": "16.0",
         "name": "loading.desktop/Baidu_warm"
     },
     {
-        "duration": "95.69785862626262",
-        "name": "loading.desktop/Bhaskar"
-    },
-    {
-        "duration": "41.749999909090896",
+        "duration": "21.0",
         "name": "loading.desktop/Bhaskar_cold"
     },
     {
-        "duration": "51.47263627272727",
+        "duration": "30.0",
         "name": "loading.desktop/Bhaskar_warm"
     },
     {
-        "duration": "77.03323236363636",
-        "name": "loading.desktop/Chosun"
-    },
-    {
-        "duration": "34.634181909090906",
+        "duration": "17.0",
         "name": "loading.desktop/Chosun_cold"
     },
     {
-        "duration": "40.61872754545455",
+        "duration": "21.0",
         "name": "loading.desktop/Chosun_warm"
     },
     {
-        "duration": "78.14680811111107",
-        "name": "loading.desktop/Colorado.edu"
-    },
-    {
-        "duration": "34.05109081818182",
+        "duration": "18.0",
         "name": "loading.desktop/Colorado.edu_cold"
     },
     {
-        "duration": "42.41045463636363",
+        "duration": "21.0",
         "name": "loading.desktop/Colorado.edu_warm"
     },
     {
-        "duration": "73.46498984343432",
-        "name": "loading.desktop/Danawa"
-    },
-    {
-        "duration": "32.620818",
+        "duration": "17.0",
         "name": "loading.desktop/Danawa_cold"
     },
     {
-        "duration": "39.22545454545454",
+        "duration": "20.0",
         "name": "loading.desktop/Danawa_warm"
     },
     {
-        "duration": "71.1682221969697",
-        "name": "loading.desktop/Daum"
-    },
-    {
-        "duration": "31.564181909090905",
+        "duration": "16.0",
         "name": "loading.desktop/Daum_cold"
     },
     {
-        "duration": "38.23954554545454",
+        "duration": "20.0",
         "name": "loading.desktop/Daum_warm"
     },
     {
-        "duration": "82.40019187878787",
-        "name": "loading.desktop/Donga"
-    },
-    {
-        "duration": "36.052727272727275",
+        "duration": "19.0",
         "name": "loading.desktop/Donga_cold"
     },
     {
-        "duration": "44.36727281818182",
+        "duration": "22.0",
         "name": "loading.desktop/Donga_warm"
     },
     {
-        "duration": "102.11448485858584",
-        "name": "loading.desktop/Economist"
-    },
-    {
-        "duration": "41.82954545454546",
+        "duration": "21.0",
         "name": "loading.desktop/Economist_cold"
     },
     {
-        "duration": "58.38845454545455",
+        "duration": "29.0",
         "name": "loading.desktop/Economist_warm"
     },
     {
-        "duration": "180.4631415050505",
-        "name": "loading.desktop/Elmundo"
-    },
-    {
-        "duration": "56.766363727272726",
+        "duration": "29.0",
         "name": "loading.desktop/Elmundo_cold"
     },
     {
-        "duration": "124.10299999999998",
-        "name": "loading.desktop/Elmundo_warm"
-    },
-    {
-        "duration": "69.69703034848486",
-        "name": "loading.desktop/FC2Blog"
-    },
-    {
-        "duration": "31.68309081818182",
+        "duration": "16.0",
         "name": "loading.desktop/FC2Blog_cold"
     },
     {
-        "duration": "36.056",
+        "duration": "19.0",
         "name": "loading.desktop/FC2Blog_warm"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "loading.desktop/FDA"
-    },
-    {
-        "duration": "75.79931317171716",
-        "name": "loading.desktop/FIFA"
-    },
-    {
-        "duration": "32.85509090909091",
+        "duration": "17.0",
         "name": "loading.desktop/FIFA_cold"
     },
     {
-        "duration": "42.29836363636364",
+        "duration": "21.0",
         "name": "loading.desktop/FIFA_warm"
     },
     {
-        "duration": "143.38708084848486",
-        "name": "loading.desktop/FarsNews"
-    },
-    {
-        "duration": "141.6059089545454",
+        "duration": "27.0",
         "name": "loading.desktop/FarsNews_cold"
     },
     {
-        "duration": "40.50745454545454",
+        "duration": "20.0",
         "name": "loading.desktop/FarsNews_warm"
     },
     {
-        "duration": "75.53585861616165",
-        "name": "loading.desktop/Flickr"
-    },
-    {
-        "duration": "32.13345436363637",
+        "duration": "16.0",
         "name": "loading.desktop/Flickr_cold"
     },
     {
-        "duration": "40.053636454545455",
+        "duration": "20.0",
         "name": "loading.desktop/Flickr_warm"
     },
     {
-        "duration": "73.68077771717172",
-        "name": "loading.desktop/FlipKart"
-    },
-    {
-        "duration": "31.75018181818182",
+        "duration": "19.0",
         "name": "loading.desktop/FlipKart_cold"
     },
     {
-        "duration": "40.299818181818175",
+        "duration": "20.0",
         "name": "loading.desktop/FlipKart_warm"
     },
     {
-        "duration": "61.55254540404039",
-        "name": "loading.desktop/Free.fr"
-    },
-    {
-        "duration": "28.31327281818182",
+        "duration": "14.0",
         "name": "loading.desktop/Free.fr_cold"
     },
     {
-        "duration": "32.280272818181814",
+        "duration": "18.0",
         "name": "loading.desktop/Free.fr_warm"
     },
     {
-        "duration": "58.197777631313116",
-        "name": "loading.desktop/HTML5Rocks"
-    },
-    {
-        "duration": "26.86945463636364",
+        "duration": "14.0",
         "name": "loading.desktop/HTML5Rocks_cold"
     },
     {
-        "duration": "30.446181772727268",
+        "duration": "16.0",
         "name": "loading.desktop/HTML5Rocks_warm"
     },
     {
-        "duration": "63.899545444444435",
-        "name": "loading.desktop/Haraj"
-    },
-    {
-        "duration": "29.686454545454545",
+        "duration": "15.0",
         "name": "loading.desktop/Haraj_cold"
     },
     {
-        "duration": "33.44236372727273",
+        "duration": "17.0",
         "name": "loading.desktop/Haraj_warm"
     },
     {
-        "duration": "92.08967675757577",
-        "name": "loading.desktop/HatenaBookmark"
-    },
-    {
-        "duration": "39.44172727272727",
+        "duration": "19.0",
         "name": "loading.desktop/HatenaBookmark_cold"
     },
     {
-        "duration": "51.46272736363637",
+        "duration": "27.0",
         "name": "loading.desktop/HatenaBookmark_warm"
     },
     {
-        "duration": "80.91992933333333",
-        "name": "loading.desktop/IGN"
-    },
-    {
-        "duration": "35.35863645454546",
+        "duration": "18.0",
         "name": "loading.desktop/IGN_cold"
     },
     {
-        "duration": "42.52245436363636",
+        "duration": "22.0",
         "name": "loading.desktop/IGN_warm"
     },
     {
-        "duration": "79.23717173737374",
-        "name": "loading.desktop/IMDB"
-    },
-    {
-        "duration": "34.606363636363646",
+        "duration": "17.0",
         "name": "loading.desktop/IMDB_cold"
     },
     {
-        "duration": "43.98918190909091",
+        "duration": "22.0",
         "name": "loading.desktop/IMDB_warm"
     },
     {
-        "duration": "80.78213134343434",
-        "name": "loading.desktop/IndiaTimes"
-    },
-    {
-        "duration": "35.079181909090906",
+        "duration": "17.0",
         "name": "loading.desktop/IndiaTimes_cold"
     },
     {
-        "duration": "44.12018190909091",
+        "duration": "22.0",
         "name": "loading.desktop/IndiaTimes_warm"
     },
     {
-        "duration": "81.66095963636364",
-        "name": "loading.desktop/Kakaku"
-    },
-    {
-        "duration": "35.228727272727276",
+        "duration": "18.0",
         "name": "loading.desktop/Kakaku_cold"
     },
     {
-        "duration": "42.783091000000006",
+        "duration": "22.0",
         "name": "loading.desktop/Kakaku_warm"
     },
     {
-        "duration": "115.41123235353534",
-        "name": "loading.desktop/Kenh14"
-    },
-    {
-        "duration": "47.85572736363636",
+        "duration": "25.0",
         "name": "loading.desktop/Kenh14_cold"
     },
     {
-        "duration": "64.74309072727273",
+        "duration": "34.0",
         "name": "loading.desktop/Kenh14_warm"
     },
     {
-        "duration": "0.0020000934",
-        "name": "loading.desktop/Leboncoin"
-    },
-    {
-        "duration": "73.09690900000003",
-        "name": "loading.desktop/Mercadolivre"
-    },
-    {
-        "duration": "34.15090913636364",
+        "duration": "16.0",
         "name": "loading.desktop/Mercadolivre_cold"
     },
     {
-        "duration": "39.20309081818181",
+        "duration": "20.0",
         "name": "loading.desktop/Mercadolivre_warm"
     },
     {
-        "duration": "83.10848609722224",
-        "name": "loading.desktop/NatGeo"
-    },
-    {
-        "duration": "67.53106070202023",
-        "name": "loading.desktop/Naver"
-    },
-    {
-        "duration": "31.20118168181818",
+        "duration": "16.0",
         "name": "loading.desktop/Naver_cold"
     },
     {
-        "duration": "35.56554554545455",
+        "duration": "18.0",
         "name": "loading.desktop/Naver_warm"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "loading.desktop/Orange"
-    },
-    {
-        "duration": "69.13476764646464",
-        "name": "loading.desktop/Pantip"
-    },
-    {
-        "duration": "31.22127277272728",
+        "duration": "16.0",
         "name": "loading.desktop/Pantip_cold"
     },
     {
-        "duration": "37.04663627272728",
+        "duration": "19.0",
         "name": "loading.desktop/Pantip_warm"
     },
     {
-        "duration": "91.78712126262629",
-        "name": "loading.desktop/PremierLeague"
-    },
-    {
-        "duration": "43.34336363636363",
+        "duration": "21.0",
         "name": "loading.desktop/PremierLeague_cold"
     },
     {
-        "duration": "51.15399981818182",
+        "duration": "27.0",
         "name": "loading.desktop/PremierLeague_warm"
     },
     {
-        "duration": "93.61086858585857",
-        "name": "loading.desktop/QQ"
-    },
-    {
-        "duration": "41.02945454545454",
+        "duration": "21.0",
         "name": "loading.desktop/QQ_cold"
     },
     {
-        "duration": "50.887818181818176",
+        "duration": "26.0",
         "name": "loading.desktop/QQ_warm"
     },
     {
-        "duration": "79.76416155555557",
-        "name": "loading.desktop/REI"
-    },
-    {
-        "duration": "34.89572727272727",
+        "duration": "18.0",
         "name": "loading.desktop/REI_cold"
     },
     {
-        "duration": "43.998636363636365",
+        "duration": "22.0",
         "name": "loading.desktop/REI_warm"
     },
     {
-        "duration": "65.75473735858588",
-        "name": "loading.desktop/Ruten"
-    },
-    {
-        "duration": "30.167090999999996",
+        "duration": "15.0",
         "name": "loading.desktop/Ruten_cold"
     },
     {
-        "duration": "33.726090818181824",
+        "duration": "17.0",
         "name": "loading.desktop/Ruten_warm"
     },
     {
-        "duration": "106.65854540404042",
-        "name": "loading.desktop/Sina"
-    },
-    {
-        "duration": "46.67527245454546",
+        "duration": "25.0",
         "name": "loading.desktop/Sina_cold"
     },
     {
-        "duration": "61.8140000909091",
+        "duration": "32.0",
         "name": "loading.desktop/Sina_warm"
     },
     {
-        "duration": "100.36073740404039",
-        "name": "loading.desktop/Taobao"
-    },
-    {
-        "duration": "44.00036363636363",
+        "duration": "25.0",
         "name": "loading.desktop/Taobao_cold"
     },
     {
-        "duration": "55.31509109090909",
+        "duration": "31.0",
         "name": "loading.desktop/Taobao_warm"
     },
     {
-        "duration": "97.96895952525253",
-        "name": "loading.desktop/TheOnion"
-    },
-    {
-        "duration": "40.10881827272727",
+        "duration": "22.0",
         "name": "loading.desktop/TheOnion_cold"
     },
     {
-        "duration": "56.237818272727274",
+        "duration": "29.0",
         "name": "loading.desktop/TheOnion_warm"
     },
     {
-        "duration": "103.5693131010101",
-        "name": "loading.desktop/TheVerge"
-    },
-    {
-        "duration": "43.66945454545455",
+        "duration": "23.0",
         "name": "loading.desktop/TheVerge_cold"
     },
     {
-        "duration": "57.977090909090904",
+        "duration": "29.0",
         "name": "loading.desktop/TheVerge_warm"
     },
     {
-        "duration": "97.86764656565656",
-        "name": "loading.desktop/TicketMaster"
-    },
-    {
-        "duration": "41.81781818181818",
+        "duration": "22.0",
         "name": "loading.desktop/TicketMaster_cold"
     },
     {
-        "duration": "53.691181818181825",
+        "duration": "28.0",
         "name": "loading.desktop/TicketMaster_warm"
     },
     {
-        "duration": "129.45020208080805",
-        "name": "loading.desktop/Vietnamnet"
-    },
-    {
-        "duration": "54.56272718181819",
+        "duration": "29.0",
         "name": "loading.desktop/Vietnamnet_cold"
     },
     {
-        "duration": "71.455",
+        "duration": "37.0",
         "name": "loading.desktop/Vietnamnet_warm"
     },
     {
-        "duration": "110.85240404040401",
-        "name": "loading.desktop/Vnexpress"
-    },
-    {
-        "duration": "45.840818181818186",
+        "duration": "24.0",
         "name": "loading.desktop/Vnexpress_cold"
     },
     {
-        "duration": "62.674091",
+        "duration": "32.0",
         "name": "loading.desktop/Vnexpress_warm"
     },
     {
-        "duration": "128.95016167676764",
-        "name": "loading.desktop/Walgreens"
-    },
-    {
-        "duration": "48.86699999999999",
+        "duration": "27.0",
         "name": "loading.desktop/Walgreens_cold"
     },
     {
-        "duration": "66.59363645454546",
+        "duration": "36.0",
         "name": "loading.desktop/Walgreens_warm"
     },
     {
-        "duration": "60.92042428282829",
-        "name": "loading.desktop/Yandex"
-    },
-    {
-        "duration": "28.47527263636364",
+        "duration": "14.0",
         "name": "loading.desktop/Yandex_cold"
     },
     {
-        "duration": "32.07054540909091",
+        "duration": "16.0",
         "name": "loading.desktop/Yandex_warm"
     },
     {
-        "duration": "0.0020000934",
-        "name": "loading.desktop/Ynet"
-    },
-    {
-        "duration": "95.01235352525256",
-        "name": "loading.desktop/amazon.co.jp"
-    },
-    {
-        "duration": "41.30800009090909",
+        "duration": "21.0",
         "name": "loading.desktop/amazon.co.jp_cold"
     },
     {
-        "duration": "52.254363454545455",
+        "duration": "26.0",
         "name": "loading.desktop/amazon.co.jp_warm"
     },
     {
-        "duration": "0.0010001659",
-        "name": "loading.desktop/goo.ne.jp"
-    },
-    {
-        "duration": "64.14469705555557",
-        "name": "loading.desktop/ja.wikipedia"
-    },
-    {
-        "duration": "29.452091",
+        "duration": "15.0",
         "name": "loading.desktop/ja.wikipedia_cold"
     },
     {
-        "duration": "33.31909127272728",
+        "duration": "17.0",
         "name": "loading.desktop/ja.wikipedia_warm"
     },
     {
-        "duration": "116.1541918585859",
-        "name": "loading.desktop/money.cnn"
-    },
-    {
-        "duration": "48.49163618181819",
+        "duration": "25.0",
         "name": "loading.desktop/money.cnn_cold"
     },
     {
-        "duration": "66.35827281818182",
+        "duration": "35.0",
         "name": "loading.desktop/money.cnn_warm"
     },
     {
-        "duration": "65.59816158585858",
-        "name": "loading.desktop/ru.wikipedia"
-    },
-    {
-        "duration": "30.597272909090908",
+        "duration": "15.0",
         "name": "loading.desktop/ru.wikipedia_cold"
     },
     {
-        "duration": "34.24136363636364",
+        "duration": "17.0",
         "name": "loading.desktop/ru.wikipedia_warm"
     },
     {
-        "duration": "130.93452529292935",
-        "name": "loading.desktop/uol.com.br"
-    },
-    {
-        "duration": "55.8129999090909",
+        "duration": "28.0",
         "name": "loading.desktop/uol.com.br_cold"
     },
     {
-        "duration": "73.41581818181818",
+        "duration": "36.0",
         "name": "loading.desktop/uol.com.br_warm"
     },
     {
-        "duration": "77.21720199999999",
-        "name": "loading.desktop/yahoo.co.jp"
-    },
-    {
-        "duration": "35.536000090909084",
+        "duration": "18.0",
         "name": "loading.desktop/yahoo.co.jp_cold"
     },
     {
-        "duration": "40.967363818181816",
+        "duration": "21.0",
         "name": "loading.desktop/yahoo.co.jp_warm"
     },
     {
-        "duration": "14.284727297979792",
+        "duration": "14.0",
         "name": "media.desktop/mse.html?media=aac_audio.mp4"
     },
     {
-        "duration": "15.291282838383838",
+        "duration": "15.0",
         "name": "media.desktop/mse.html?media=aac_audio.mp4,h264_video.mp4"
     },
     {
-        "duration": "15.404494974747472",
+        "duration": "15.0",
         "name": "media.desktop/mse.html?media=aac_audio.mp4,h264_video.mp4&waitForPageLoaded=true"
     },
     {
-        "duration": "14.54688892929293",
+        "duration": "15.0",
         "name": "media.desktop/mse.html?media=h264_video.mp4"
     },
     {
-        "duration": "30.074434353535352",
+        "duration": "22.0",
         "name": "media.desktop/video.html?src=crowd.ogg&type=audio"
     },
     {
-        "duration": "22.585696989898995",
+        "duration": "23.0",
         "name": "media.desktop/video.html?src=crowd1080.mp4"
     },
     {
-        "duration": "22.32874746464647",
+        "duration": "23.0",
         "name": "media.desktop/video.html?src=crowd1080.webm"
     },
     {
-        "duration": "20.64434349494949",
+        "duration": "21.0",
         "name": "media.desktop/video.html?src=crowd1080_vp9.webm"
     },
     {
-        "duration": "11.109717166666664",
+        "duration": "12.0",
         "name": "media.desktop/video.html?src=crowd1080_vp9.webm&seek"
     },
     {
-        "duration": "20.519212151515166",
+        "duration": "21.0",
         "name": "media.desktop/video.html?src=crowd720_vp9.webm"
     },
     {
-        "duration": "22.698989939393936",
+        "duration": "23.0",
         "name": "media.desktop/video.html?src=garden2_10s.mp4"
     },
     {
-        "duration": "13.125444494949496",
+        "duration": "14.0",
         "name": "media.desktop/video.html?src=garden2_10s.mp4&seek"
     },
     {
-        "duration": "21.584535383838386",
+        "duration": "22.0",
         "name": "media.desktop/video.html?src=garden2_10s.webm"
     },
     {
-        "duration": "11.604767681818181",
+        "duration": "12.0",
         "name": "media.desktop/video.html?src=garden2_10s.webm&seek"
     },
     {
-        "duration": "13.741343424242428",
+        "duration": "14.0",
         "name": "media.desktop/video.html?src=smpte_3840x2160_60fps_vp9.webm&seek"
     },
     {
-        "duration": "28.402000010101023",
+        "duration": "29.0",
         "name": "media.desktop/video.html?src=tulip2.m4a&type=audio"
     },
     {
-        "duration": "28.308464636363627",
+        "duration": "29.0",
         "name": "media.desktop/video.html?src=tulip2.mp3&type=audio"
     },
     {
-        "duration": "10.517202010101009",
+        "duration": "11.0",
         "name": "media.desktop/video.html?src=tulip2.mp3&type=audio&seek"
     },
     {
-        "duration": "30.34575756565656",
+        "duration": "31.0",
         "name": "media.desktop/video.html?src=tulip2.mp4"
     },
     {
-        "duration": "31.075262636363636",
+        "duration": "32.0",
         "name": "media.desktop/video.html?src=tulip2.mp4&busyjs"
     },
     {
-        "duration": "12.047656540404038",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=tulip2.mp4&seek"
     },
     {
-        "duration": "28.44826266666668",
+        "duration": "29.0",
         "name": "media.desktop/video.html?src=tulip2.ogg&type=audio"
     },
     {
-        "duration": "10.554030308080806",
+        "duration": "11.0",
         "name": "media.desktop/video.html?src=tulip2.ogg&type=audio&seek"
     },
     {
-        "duration": "30.347424181818187",
+        "duration": "31.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm"
     },
     {
-        "duration": "22.295969666666664",
+        "duration": "23.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm&background"
     },
     {
-        "duration": "12.51783844444445",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm&seek"
     },
     {
-        "duration": "30.544848464646467",
-        "name": "media.desktop/video.html?src=tulip2.vp9.webm_Regular-3G"
-    },
-    {
-        "duration": "28.388313070707053",
+        "duration": "29.0",
         "name": "media.desktop/video.html?src=tulip2.wav&type=audio"
     },
     {
-        "duration": "10.554636378787874",
+        "duration": "11.0",
         "name": "media.desktop/video.html?src=tulip2.wav&type=audio&seek"
     },
     {
-        "duration": "127.33676775757577",
+        "duration": "95.0",
         "name": "memory.desktop/TrivialAnimationPageSharedPageState"
     },
     {
-        "duration": "145.83215154545456",
+        "duration": "80.0",
         "name": "memory.desktop/TrivialBlinkingCursorPageSharedPageState"
     },
     {
-        "duration": "139.11132333333333",
+        "duration": "77.0",
         "name": "memory.desktop/TrivialBlurAnimationPageSharedPageState"
     },
     {
-        "duration": "140.222798010101",
+        "duration": "82.0",
         "name": "memory.desktop/TrivialCanvasPageSharedPageState"
     },
     {
-        "duration": "146.12095961616163",
+        "duration": "85.0",
         "name": "memory.desktop/TrivialFullscreenVideoPageSharedPageState"
     },
     {
-        "duration": "139.2347374848485",
+        "duration": "82.0",
         "name": "memory.desktop/TrivialGifPageSharedPageState"
     },
     {
-        "duration": "151.88948483838388",
+        "duration": "87.0",
         "name": "memory.desktop/TrivialScrollingPageSharedPageState"
     },
     {
-        "duration": "140.38805041414145",
+        "duration": "76.0",
         "name": "memory.desktop/TrivialWebGLPageSharedPageState"
     },
     {
-        "duration": "176.53833333333338",
+        "duration": "224.0",
         "name": "memory.long_running_idle_gmail_background_tbmv2/https://mail.google.com/mail/"
     },
     {
-        "duration": "179.30326292929288",
+        "duration": "182.0",
         "name": "memory.long_running_idle_gmail_tbmv2/https://mail.google.com/mail/"
     },
     {
-        "duration": "51.14163640404042",
+        "duration": "37.0",
         "name": "octane/http://chromium.github.io/octane/index.html?auto=1"
     },
     {
-        "duration": "0.016000032",
-        "name": "oortonline_tbmv2/http://oortonline.gl/#run"
-    },
-    {
-        "duration": "45.30037377777777",
+        "duration": "46.0",
         "name": "power.desktop/TrivialAnimationPageSharedPageState"
     },
     {
-        "duration": "42.370767616161636",
+        "duration": "43.0",
         "name": "power.desktop/TrivialBlinkingCursorPageSharedPageState"
     },
     {
-        "duration": "45.103060626262646",
+        "duration": "46.0",
         "name": "power.desktop/TrivialBlurAnimationPageSharedPageState"
     },
     {
-        "duration": "44.91517175757577",
+        "duration": "45.0",
         "name": "power.desktop/TrivialCanvasPageSharedPageState"
     },
     {
-        "duration": "43.55830305050504",
+        "duration": "44.0",
         "name": "power.desktop/TrivialFullscreenVideoPageSharedPageState"
     },
     {
-        "duration": "41.65617175757575",
+        "duration": "43.0",
         "name": "power.desktop/TrivialGifPageSharedPageState"
     },
     {
-        "duration": "60.67017167676768",
+        "duration": "45.0",
         "name": "power.desktop/TrivialScrollingPageSharedPageState"
     },
     {
-        "duration": "45.631141434343434",
+        "duration": "46.0",
         "name": "power.desktop/TrivialWebGLPageSharedPageState"
     },
     {
-        "duration": "48.99010101010105",
+        "duration": "50.0",
         "name": "power.desktop/abcnews"
     },
     {
-        "duration": "42.73526260606061",
+        "duration": "44.0",
         "name": "power.desktop/indiatimes"
     },
     {
-        "duration": "45.23994945454546",
+        "duration": "46.0",
         "name": "power.desktop/instagram"
     },
     {
-        "duration": "42.91129294949496",
+        "duration": "44.0",
         "name": "power.desktop/microsoft"
     },
     {
-        "duration": "44.993212141414126",
+        "duration": "45.0",
         "name": "power.desktop/sina"
     },
     {
-        "duration": "45.198464585858595",
+        "duration": "46.0",
         "name": "power.desktop/slideshare"
     },
     {
-        "duration": "51.8506162020202",
+        "duration": "54.0",
         "name": "power.desktop/uol"
     },
     {
-        "duration": "44.42340401717171",
+        "duration": "7.0",
         "name": "rasterize_and_record_micro.partial_invalidation/800_relpos_divs.html"
     },
     {
-        "duration": "40.14971717171717",
+        "duration": "19.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/amazon.html"
     },
     {
-        "duration": "10.36961614141414",
+        "duration": "11.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/blogger.html"
     },
     {
-        "duration": "11.474747515151515",
+        "duration": "12.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/booking.html"
     },
     {
-        "duration": "14.137484863636368",
+        "duration": "14.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/cnn.html"
     },
     {
-        "duration": "11.30878783838383",
+        "duration": "12.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/ebay.html"
     },
     {
-        "duration": "18.503888858585857",
+        "duration": "19.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/espn.html"
     },
     {
-        "duration": "10.994060601010094",
+        "duration": "11.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/facebook.html"
     },
     {
-        "duration": "10.46459592929293",
+        "duration": "11.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/gmail.html"
     },
     {
-        "duration": "9.05187877777778",
+        "duration": "10.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/google.html"
     },
     {
-        "duration": "7.8801414030303025",
+        "duration": "8.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googlecalendar.html"
     },
     {
-        "duration": "8.841080797979798",
+        "duration": "9.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googledocs.html"
     },
     {
-        "duration": "14.022161646464642",
+        "duration": "15.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googleimagesearch.html"
     },
     {
-        "duration": "23.136989878787876",
+        "duration": "23.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googleplus.html"
     },
     {
-        "duration": "9.614131297979798",
+        "duration": "10.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/linkedin.html"
     },
     {
-        "duration": "8.085515150505051",
+        "duration": "9.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/pinterest.html"
     },
     {
-        "duration": "27.01127273737374",
+        "duration": "27.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/techcrunch.html"
     },
     {
-        "duration": "17.37996967676768",
+        "duration": "18.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/twitter.html"
     },
     {
-        "duration": "13.90968686363636",
+        "duration": "14.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/weather.html"
     },
     {
-        "duration": "0.0015000105",
-        "name": "rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html"
-    },
-    {
-        "duration": "17.52616165656566",
+        "duration": "20.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/wordpress.html"
     },
     {
-        "duration": "12.048848499999997",
+        "duration": "13.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahooanswers.html"
     },
     {
-        "duration": "23.689646464646458",
+        "duration": "24.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoogames.html"
     },
     {
-        "duration": "101.4227676363636",
+        "duration": "102.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoonews.html"
     },
     {
-        "duration": "87.58763624242427",
+        "duration": "88.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoosports.html"
     },
     {
-        "duration": "25.368646454545452",
+        "duration": "26.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/youtube.html"
     },
     {
-        "duration": "11.749513483783783",
+        "duration": "34.0",
+        "name": "rendering.desktop/accu_weather_2018"
+    },
+    {
+        "duration": "6.0",
+        "name": "rendering.desktop/accu_weather_pinch_2018"
+    },
+    {
+        "duration": "33.0",
+        "name": "rendering.desktop/amazon_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/amazon_pinch"
     },
     {
-        "duration": "29.648757585858586",
+        "duration": "6.0",
+        "name": "rendering.desktop/amazon_pinch_2018"
+    },
+    {
+        "duration": "26.0",
         "name": "rendering.desktop/analog_clock_svg"
     },
     {
-        "duration": "31.3422702972973",
+        "duration": "27.0",
         "name": "rendering.desktop/animometer_webgl"
     },
     {
-        "duration": "25.6781891891892",
+        "duration": "27.0",
         "name": "rendering.desktop/aquarium"
     },
     {
-        "duration": "33.15567567567567",
+        "duration": "36.0",
         "name": "rendering.desktop/aquarium_20k"
     },
     {
-        "duration": "26.025228571428574",
+        "duration": "28.0",
         "name": "rendering.desktop/background_color_animation"
     },
     {
-        "duration": "27.911499971428572",
+        "duration": "30.0",
         "name": "rendering.desktop/background_color_animation_with_gradient"
     },
     {
-        "duration": "23.35797962244898",
+        "duration": "26.0",
         "name": "rendering.desktop/balls_css_key_frame_animations"
     },
     {
-        "duration": "22.68637757142857",
+        "duration": "25.0",
         "name": "rendering.desktop/balls_css_key_frame_animations_composited_transform"
     },
     {
-        "duration": "28.071877602040814",
+        "duration": "31.0",
         "name": "rendering.desktop/balls_css_transition_2_properties"
     },
     {
-        "duration": "28.14669385714286",
+        "duration": "31.0",
         "name": "rendering.desktop/balls_css_transition_40_properties"
     },
     {
-        "duration": "28.141449020408146",
+        "duration": "31.0",
         "name": "rendering.desktop/balls_css_transition_all_properties"
     },
     {
-        "duration": "28.019132591836726",
+        "duration": "28.0",
         "name": "rendering.desktop/balls_javascript_canvas"
     },
     {
-        "duration": "23.552336744897968",
+        "duration": "28.0",
         "name": "rendering.desktop/balls_javascript_css"
     },
     {
-        "duration": "26.56185711224489",
+        "duration": "29.0",
         "name": "rendering.desktop/balls_svg_animations"
     },
     {
-        "duration": "21.239837851351353",
+        "duration": "23.0",
         "name": "rendering.desktop/blob"
     },
     {
-        "duration": "27.214393919191902",
-        "name": "rendering.desktop/blogspot"
+        "duration": "37.0",
+        "name": "rendering.desktop/blogspot_2018"
     },
     {
-        "duration": "3.398148660810811",
+        "duration": "4.0",
         "name": "rendering.desktop/blogspot_pinch"
     },
     {
-        "duration": "16.276090944444448",
-        "name": "rendering.desktop/booking.com"
+        "duration": "6.0",
+        "name": "rendering.desktop/blogspot_pinch_2018"
     },
     {
-        "duration": "3.3600540621621624",
+        "duration": "21.0",
+        "name": "rendering.desktop/booking.com_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/booking_pinch"
     },
     {
-        "duration": "16.071454550505045",
+        "duration": "6.0",
+        "name": "rendering.desktop/booking_pinch_2018"
+    },
+    {
+        "duration": "18.0",
         "name": "rendering.desktop/bouncing_balls_15"
     },
     {
-        "duration": "16.618626292929292",
+        "duration": "22.0",
         "name": "rendering.desktop/bouncing_balls_shadow"
     },
     {
-        "duration": "17.947232348484853",
+        "duration": "22.0",
         "name": "rendering.desktop/bouncing_clipped_rectangles"
     },
     {
-        "duration": "18.87498991414141",
+        "duration": "19.0",
         "name": "rendering.desktop/bouncing_gradient_circles"
     },
     {
-        "duration": "13.914151474747479",
+        "duration": "15.0",
         "name": "rendering.desktop/bouncing_png_images"
     },
     {
-        "duration": "25.59261617171718",
+        "duration": "29.0",
         "name": "rendering.desktop/bouncing_svg_images"
     },
     {
-        "duration": "19.723135148648645",
+        "duration": "21.0",
         "name": "rendering.desktop/canvas_05000_pixels_per_second"
     },
     {
-        "duration": "18.904567567567568",
+        "duration": "20.0",
         "name": "rendering.desktop/canvas_10000_pixels_per_second"
     },
     {
-        "duration": "16.27175674324324",
+        "duration": "17.0",
         "name": "rendering.desktop/canvas_15000_pixels_per_second"
     },
     {
-        "duration": "14.953283729729732",
+        "duration": "16.0",
         "name": "rendering.desktop/canvas_20000_pixels_per_second"
     },
     {
-        "duration": "13.580216250000005",
+        "duration": "14.0",
         "name": "rendering.desktop/canvas_30000_pixels_per_second"
     },
     {
-        "duration": "12.205743222972975",
+        "duration": "13.0",
         "name": "rendering.desktop/canvas_40000_pixels_per_second"
     },
     {
-        "duration": "11.751648675675678",
+        "duration": "13.0",
         "name": "rendering.desktop/canvas_50000_pixels_per_second"
     },
     {
-        "duration": "11.394418939189187",
+        "duration": "12.0",
         "name": "rendering.desktop/canvas_60000_pixels_per_second"
     },
     {
-        "duration": "11.054716209459457",
+        "duration": "12.0",
         "name": "rendering.desktop/canvas_75000_pixels_per_second"
     },
     {
-        "duration": "10.93420270945946",
+        "duration": "12.0",
         "name": "rendering.desktop/canvas_90000_pixels_per_second"
     },
     {
-        "duration": "18.635040444444442",
+        "duration": "22.0",
         "name": "rendering.desktop/canvas_animation_no_clear"
     },
     {
-        "duration": "17.480787883838378",
+        "duration": "18.0",
         "name": "rendering.desktop/canvas_arcs"
     },
     {
-        "duration": "16.069838378787882",
+        "duration": "18.0",
         "name": "rendering.desktop/canvas_font_cycler"
     },
     {
-        "duration": "16.083666671717182",
+        "duration": "18.0",
         "name": "rendering.desktop/canvas_lines"
     },
     {
-        "duration": "16.040707101010103",
+        "duration": "18.0",
         "name": "rendering.desktop/canvas_to_blob"
     },
     {
-        "duration": "14.130229729729738",
+        "duration": "14.0",
         "name": "rendering.desktop/cats_unscaled"
     },
     {
-        "duration": "11.663405418918924",
+        "duration": "13.0",
         "name": "rendering.desktop/cats_viewport_width"
     },
     {
-        "duration": "19.4661413939394",
+        "duration": "27.0",
+        "name": "rendering.desktop/cc_poster_circle"
+    },
+    {
+        "duration": "25.0",
+        "name": "rendering.desktop/cc_scroll_200_layer_grid"
+    },
+    {
+        "duration": "18.0",
+        "name": "rendering.desktop/cc_scroll_text_only"
+    },
+    {
+        "duration": "22.0",
         "name": "rendering.desktop/chip_tune"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "rendering.desktop/cnn"
+        "duration": "38.0",
+        "name": "rendering.desktop/cnn_2018"
     },
     {
-        "duration": "3.355621628378379",
+        "duration": "4.0",
         "name": "rendering.desktop/cnn_pinch"
     },
     {
-        "duration": "21.967346938775506",
+        "duration": "6.0",
+        "name": "rendering.desktop/cnn_pinch_2018"
+    },
+    {
+        "duration": "24.0",
         "name": "rendering.desktop/compositor_heavy_animation"
     },
     {
-        "duration": "18.872939378787883",
+        "duration": "21.0",
         "name": "rendering.desktop/crafty_mind"
     },
     {
-        "duration": "21.48962241836734",
+        "duration": "24.0",
         "name": "rendering.desktop/css_animations_many_keyframes"
     },
     {
-        "duration": "21.739224469387757",
+        "duration": "24.0",
         "name": "rendering.desktop/css_animations_simultaneous_inline_style"
     },
     {
-        "duration": "22.285142887755097",
+        "duration": "25.0",
         "name": "rendering.desktop/css_animations_simultaneous_new_element"
     },
     {
-        "duration": "21.638183663265313",
+        "duration": "24.0",
         "name": "rendering.desktop/css_animations_simultaneous_style_element"
     },
     {
-        "duration": "21.801836724489807",
+        "duration": "24.0",
         "name": "rendering.desktop/css_animations_simultaneous_updating_class"
     },
     {
-        "duration": "20.921612224489795",
+        "duration": "23.0",
         "name": "rendering.desktop/css_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "23.98542856122449",
+        "duration": "27.0",
         "name": "rendering.desktop/css_animations_staggered_inline_style"
     },
     {
-        "duration": "25.03437756122449",
+        "duration": "28.0",
         "name": "rendering.desktop/css_animations_staggered_new_element"
     },
     {
-        "duration": "24.63691838775511",
+        "duration": "28.0",
         "name": "rendering.desktop/css_animations_staggered_style_element"
     },
     {
-        "duration": "24.100163255102036",
+        "duration": "27.0",
         "name": "rendering.desktop/css_animations_staggered_updating_class"
     },
     {
-        "duration": "24.08099997959184",
+        "duration": "27.0",
         "name": "rendering.desktop/css_animations_triggered_inline_style"
     },
     {
-        "duration": "25.08975509183673",
+        "duration": "28.0",
         "name": "rendering.desktop/css_animations_triggered_new_element"
     },
     {
-        "duration": "24.66866327551021",
+        "duration": "28.0",
         "name": "rendering.desktop/css_animations_triggered_style_element"
     },
     {
-        "duration": "24.05020411224491",
+        "duration": "27.0",
         "name": "rendering.desktop/css_animations_triggered_updating_class"
     },
     {
-        "duration": "21.854663255102032",
+        "duration": "24.0",
         "name": "rendering.desktop/css_transitions_inline_style"
     },
     {
-        "duration": "22.405316326530603",
+        "duration": "25.0",
         "name": "rendering.desktop/css_transitions_new_element"
     },
     {
-        "duration": "22.588540826530604",
+        "duration": "25.0",
         "name": "rendering.desktop/css_transitions_staggered_inline_style"
     },
     {
-        "duration": "22.92858166326531",
+        "duration": "26.0",
         "name": "rendering.desktop/css_transitions_staggered_new_element"
     },
     {
-        "duration": "22.545020357142857",
+        "duration": "25.0",
         "name": "rendering.desktop/css_transitions_staggered_style_element"
     },
     {
-        "duration": "22.164714285714282",
+        "duration": "25.0",
         "name": "rendering.desktop/css_transitions_staggered_updating_class"
     },
     {
-        "duration": "21.855704112244904",
+        "duration": "24.0",
         "name": "rendering.desktop/css_transitions_style_element"
     },
     {
-        "duration": "24.090683673469385",
+        "duration": "27.0",
         "name": "rendering.desktop/css_transitions_triggered_inline_style"
     },
     {
-        "duration": "24.180387755102036",
+        "duration": "27.0",
         "name": "rendering.desktop/css_transitions_triggered_new_element"
     },
     {
-        "duration": "24.250428520408153",
+        "duration": "27.0",
         "name": "rendering.desktop/css_transitions_triggered_style_element"
     },
     {
-        "duration": "24.188265285714287",
+        "duration": "27.0",
         "name": "rendering.desktop/css_transitions_triggered_updating_class"
     },
     {
-        "duration": "22.349540795918358",
+        "duration": "24.0",
         "name": "rendering.desktop/css_transitions_updating_class"
     },
     {
-        "duration": "21.67029589795918",
+        "duration": "24.0",
         "name": "rendering.desktop/css_value_type_color"
     },
     {
-        "duration": "46.88489804081632",
+        "duration": "52.0",
         "name": "rendering.desktop/css_value_type_filter"
     },
     {
-        "duration": "22.139653020408165",
+        "duration": "25.0",
         "name": "rendering.desktop/css_value_type_length"
     },
     {
-        "duration": "23.012999989795908",
+        "duration": "24.0",
         "name": "rendering.desktop/css_value_type_length_complex"
     },
     {
-        "duration": "22.605897989795913",
+        "duration": "24.0",
         "name": "rendering.desktop/css_value_type_length_simple"
     },
     {
-        "duration": "23.596938744897944",
+        "duration": "26.0",
         "name": "rendering.desktop/css_value_type_path"
     },
     {
-        "duration": "24.968959183673462",
+        "duration": "28.0",
         "name": "rendering.desktop/css_value_type_shadow"
     },
     {
-        "duration": "22.006602020408145",
+        "duration": "25.0",
         "name": "rendering.desktop/css_value_type_transform_complex"
     },
     {
-        "duration": "22.39977551020408",
+        "duration": "25.0",
         "name": "rendering.desktop/css_value_type_transform_simple"
     },
     {
-        "duration": "22.424216216216212",
+        "duration": "24.0",
         "name": "rendering.desktop/dynamic_cube_map"
     },
     {
-        "duration": "22.056729675675676",
+        "duration": "23.0",
         "name": "rendering.desktop/earth"
     },
     {
-        "duration": "14.417717176767686",
-        "name": "rendering.desktop/ebay"
+        "duration": "24.0",
+        "name": "rendering.desktop/ebay_2018"
     },
     {
-        "duration": "3.3867432459459463",
+        "duration": "4.0",
         "name": "rendering.desktop/ebay_pinch"
     },
     {
-        "duration": "20.23591921212121",
+        "duration": "6.0",
+        "name": "rendering.desktop/ebay_pinch_2018"
+    },
+    {
+        "duration": "22.0",
         "name": "rendering.desktop/effect_games"
     },
     {
-        "duration": "17.596323212121213",
-        "name": "rendering.desktop/espn"
+        "duration": "28.0",
+        "name": "rendering.desktop/espn_2018"
     },
     {
-        "duration": "1.9492026716216213",
+        "duration": "4.0",
         "name": "rendering.desktop/espn_pinch"
     },
     {
-        "duration": "24.38280001428571",
+        "duration": "6.0",
+        "name": "rendering.desktop/espn_pinch_2018"
+    },
+    {
+        "duration": "27.0",
         "name": "rendering.desktop/extra_large_texture_uploads"
     },
     {
-        "duration": "16.001151525252535",
-        "name": "rendering.desktop/facebook"
+        "duration": "22.0",
+        "name": "rendering.desktop/facebook_2018"
     },
     {
-        "duration": "3.3825405540540543",
+        "duration": "4.0",
         "name": "rendering.desktop/facebook_pinch"
     },
     {
-        "duration": "17.90641415656566",
+        "duration": "6.0",
+        "name": "rendering.desktop/facebook_pinch_2018"
+    },
+    {
+        "duration": "19.0",
         "name": "rendering.desktop/fill_shapes"
     },
     {
-        "duration": "24.849848494949494",
+        "duration": "26.0",
         "name": "rendering.desktop/filter_terrain_svg"
     },
     {
-        "duration": "16.42275757070707",
+        "duration": "17.0",
         "name": "rendering.desktop/geo_apis"
     },
     {
-        "duration": "46.080464656565645",
-        "name": "rendering.desktop/gmail"
+        "duration": "25.0",
+        "name": "rendering.desktop/gmail_2018"
     },
     {
-        "duration": "3.430027028378378",
+        "duration": "53.0",
+        "name": "rendering.desktop/gmail_move_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/gmail_pinch"
     },
     {
-        "duration": "2.003162155405405",
+        "duration": "6.0",
+        "name": "rendering.desktop/gmail_pinch_2018"
+    },
+    {
+        "duration": "21.0",
+        "name": "rendering.desktop/google_calendar_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/google_calendar_pinch"
     },
     {
-        "duration": "1.9667432216216216",
+        "duration": "6.0",
+        "name": "rendering.desktop/google_calendar_pinch_2018"
+    },
+    {
+        "duration": "22.0",
+        "name": "rendering.desktop/google_docs_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/google_image_pinch"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "rendering.desktop/google_image_search"
+        "duration": "6.0",
+        "name": "rendering.desktop/google_image_pinch_2018"
     },
     {
-        "duration": "3.4238783621621613",
+        "duration": "23.0",
+        "name": "rendering.desktop/google_image_search_2018"
+    },
+    {
+        "duration": "23.0",
+        "name": "rendering.desktop/google_plus_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/google_search_pinch"
     },
     {
-        "duration": "13.695181843434337",
-        "name": "rendering.desktop/google_web_search"
+        "duration": "6.0",
+        "name": "rendering.desktop/google_search_pinch_2018"
     },
     {
-        "duration": "24.932464656565646",
+        "duration": "20.0",
+        "name": "rendering.desktop/google_web_search_2018"
+    },
+    {
+        "duration": "27.0",
         "name": "rendering.desktop/guimark_vector_chart"
     },
     {
-        "duration": "18.654545434343426",
+        "duration": "21.0",
         "name": "rendering.desktop/hakim"
     },
     {
-        "duration": "33.754171707070725",
+        "duration": "35.0",
         "name": "rendering.desktop/ie_chalkboard"
     },
     {
-        "duration": "28.128818171717178",
+        "duration": "31.0",
         "name": "rendering.desktop/ie_pirate_mark"
     },
     {
-        "duration": "19.5751313131313",
+        "duration": "24.0",
         "name": "rendering.desktop/jarro_doverson"
     },
     {
-        "duration": "18.821999989898988",
+        "duration": "36.0",
+        "name": "rendering.desktop/js_full_screen_invalidation"
+    },
+    {
+        "duration": "28.0",
+        "name": "rendering.desktop/js_poster_circle"
+    },
+    {
+        "duration": "25.0",
+        "name": "rendering.desktop/js_scroll_200_layer_grid"
+    },
+    {
+        "duration": "25.0",
+        "name": "rendering.desktop/js_scroll_text_only"
+    },
+    {
+        "duration": "21.0",
         "name": "rendering.desktop/kevs_3d"
     },
     {
-        "duration": "20.936061244897964",
+        "duration": "23.0",
         "name": "rendering.desktop/keyframed_animations"
     },
     {
-        "duration": "24.960199999999997",
+        "duration": "27.0",
         "name": "rendering.desktop/large_texture_uploads"
     },
     {
-        "duration": "16.06519193939393",
-        "name": "rendering.desktop/linkedin"
+        "duration": "26.0",
+        "name": "rendering.desktop/linkedin_2018"
     },
     {
-        "duration": "3.3957837581081085",
+        "duration": "4.0",
         "name": "rendering.desktop/linkedin_pinch"
     },
     {
-        "duration": "19.803989898989897",
+        "duration": "6.0",
+        "name": "rendering.desktop/linkedin_pinch_2018"
+    },
+    {
+        "duration": "22.0",
         "name": "rendering.desktop/man_in_blue"
     },
     {
-        "duration": "20.679333343434344",
+        "duration": "24.0",
         "name": "rendering.desktop/many_images"
     },
     {
-        "duration": "21.30737837837838",
+        "duration": "23.0",
         "name": "rendering.desktop/many_planets_deep"
     },
     {
-        "duration": "20.254111121212123",
-        "name": "rendering.desktop/maps_move"
+        "duration": "24.0",
+        "name": "rendering.desktop/maps_move_2018"
     },
     {
-        "duration": "23.513500000000004",
+        "duration": "26.0",
         "name": "rendering.desktop/maps_perf_test"
     },
     {
-        "duration": "23.8306857",
+        "duration": "26.0",
         "name": "rendering.desktop/medium_texture_uploads"
     },
     {
-        "duration": "17.122121166666663",
+        "duration": "19.0",
         "name": "rendering.desktop/megi_dish"
     },
     {
-        "duration": "17.747333348484844",
+        "duration": "20.0",
         "name": "rendering.desktop/microsoft_asteroid_belt"
     },
     {
-        "duration": "25.96921209090908",
+        "duration": "28.0",
         "name": "rendering.desktop/microsoft_fireflies"
     },
     {
-        "duration": "17.80268685858586",
+        "duration": "20.0",
         "name": "rendering.desktop/microsoft_fish_ie_tank"
     },
     {
-        "duration": "17.789606075757575",
+        "duration": "19.0",
         "name": "rendering.desktop/microsoft_snow"
     },
     {
-        "duration": "16.500323262626264",
+        "duration": "18.0",
         "name": "rendering.desktop/microsoft_speed_reading"
     },
     {
-        "duration": "17.030828313131316",
+        "duration": "19.0",
         "name": "rendering.desktop/microsoft_tweet_map"
     },
     {
-        "duration": "22.418767666666664",
+        "duration": "25.0",
         "name": "rendering.desktop/microsoft_video_city"
     },
     {
-        "duration": "17.979404080808084",
+        "duration": "20.0",
         "name": "rendering.desktop/microsoft_worker_fountains"
     },
     {
-        "duration": "16.28039394949495",
+        "duration": "18.0",
         "name": "rendering.desktop/mix_10k"
     },
     {
-        "duration": "20.562163306122454",
+        "duration": "22.0",
         "name": "rendering.desktop/mix_blend_mode_animation_difference"
     },
     {
-        "duration": "20.540653061224486",
+        "duration": "22.0",
         "name": "rendering.desktop/mix_blend_mode_animation_hue"
     },
     {
-        "duration": "23.503153051020416",
+        "duration": "26.0",
         "name": "rendering.desktop/mix_blend_mode_animation_propagating_isolation"
     },
     {
-        "duration": "21.31911221428572",
+        "duration": "24.0",
         "name": "rendering.desktop/mix_blend_mode_animation_screen"
     },
     {
-        "duration": "25.787787888888882",
+        "duration": "26.0",
         "name": "rendering.desktop/motion_mark_canvas_fill_shapes"
     },
     {
-        "duration": "29.423434353535352",
+        "duration": "25.0",
         "name": "rendering.desktop/motion_mark_canvas_stroke_shapes"
     },
     {
-        "duration": "29.478848494949478",
+        "duration": "32.0",
         "name": "rendering.desktop/motion_mark_focus"
     },
     {
-        "duration": "22.122202648648646",
+        "duration": "32.0",
+        "name": "rendering.desktop/new_tilings"
+    },
+    {
+        "duration": "23.0",
         "name": "rendering.desktop/nvidia_vertex_buffer_object"
     },
     {
-        "duration": "43.261857081632634",
+        "duration": "45.0",
         "name": "rendering.desktop/overlay_background_color_css_transitions_page"
     },
     {
-        "duration": "19.93382433783784",
+        "duration": "22.0",
         "name": "rendering.desktop/particles"
     },
     {
-        "duration": "22.1771211919192",
-        "name": "rendering.desktop/pinterest"
+        "duration": "31.0",
+        "name": "rendering.desktop/pinterest_2018"
     },
     {
-        "duration": "17.12040403030303",
+        "duration": "20.0",
         "name": "rendering.desktop/put_get_image_data"
     },
     {
-        "duration": "20.72282862857143",
+        "duration": "21.0",
         "name": "rendering.desktop/raf"
     },
     {
-        "duration": "19.898342842857137",
+        "duration": "21.0",
         "name": "rendering.desktop/raf_animation"
     },
     {
-        "duration": "19.21491427142857",
+        "duration": "21.0",
         "name": "rendering.desktop/raf_canvas"
     },
     {
-        "duration": "19.894214342857143",
+        "duration": "21.0",
         "name": "rendering.desktop/raf_touch_animation"
     },
     {
-        "duration": "16.730949545454546",
+        "duration": "18.0",
         "name": "rendering.desktop/runway"
     },
     {
-        "duration": "20.584945932432436",
+        "duration": "22.0",
         "name": "rendering.desktop/san_angeles"
     },
     {
-        "duration": "11.322185735714287",
+        "duration": "12.0",
         "name": "rendering.desktop/second_batch_js_heavy"
     },
     {
-        "duration": "11.337228557142856",
+        "duration": "12.0",
         "name": "rendering.desktop/second_batch_js_light"
     },
     {
-        "duration": "11.281528657142855",
+        "duration": "12.0",
         "name": "rendering.desktop/second_batch_js_medium"
     },
     {
-        "duration": "18.043371428571433",
+        "duration": "20.0",
         "name": "rendering.desktop/simple_text_page"
     },
     {
-        "duration": "14.075828578571427",
+        "duration": "15.0",
         "name": "rendering.desktop/simple_touch_drag"
     },
     {
-        "duration": "23.387328628571424",
+        "duration": "25.0",
         "name": "rendering.desktop/small_texture_uploads"
     },
     {
-        "duration": "19.919131328282827",
+        "duration": "23.0",
         "name": "rendering.desktop/smash_cat"
     },
     {
-        "duration": "15.738959590909094",
+        "duration": "17.0",
         "name": "rendering.desktop/spielzeugz"
     },
     {
-        "duration": "20.060242444444444",
+        "duration": "18.0",
         "name": "rendering.desktop/stroke_shapes"
     },
     {
-        "duration": "16.70578568571429",
+        "duration": "18.0",
         "name": "rendering.desktop/sync_scroll_offset"
     },
     {
-        "duration": "45.047010141414134",
-        "name": "rendering.desktop/techcrunch"
+        "duration": "31.0",
+        "name": "rendering.desktop/techcrunch_2018"
     },
     {
-        "duration": "18.489094567567573",
+        "duration": "20.0",
         "name": "rendering.desktop/text_05000_pixels_per_second"
     },
     {
-        "duration": "18.111351310810807",
+        "duration": "19.0",
         "name": "rendering.desktop/text_10000_pixels_per_second"
     },
     {
-        "duration": "15.123216229729724",
+        "duration": "16.0",
         "name": "rendering.desktop/text_15000_pixels_per_second"
     },
     {
-        "duration": "13.47327028378379",
+        "duration": "15.0",
         "name": "rendering.desktop/text_20000_pixels_per_second"
     },
     {
-        "duration": "12.086702675675676",
+        "duration": "13.0",
         "name": "rendering.desktop/text_30000_pixels_per_second"
     },
     {
-        "duration": "11.470148682432429",
+        "duration": "12.0",
         "name": "rendering.desktop/text_40000_pixels_per_second"
     },
     {
-        "duration": "11.046702682432436",
+        "duration": "12.0",
         "name": "rendering.desktop/text_50000_pixels_per_second"
     },
     {
-        "duration": "10.755243263513508",
+        "duration": "12.0",
         "name": "rendering.desktop/text_60000_pixels_per_second"
     },
     {
-        "duration": "10.538932418918922",
+        "duration": "11.0",
         "name": "rendering.desktop/text_75000_pixels_per_second"
     },
     {
-        "duration": "10.363324270270269",
+        "duration": "11.0",
         "name": "rendering.desktop/text_90000_pixels_per_second"
     },
     {
-        "duration": "21.405027054054052",
+        "duration": "23.0",
         "name": "rendering.desktop/text_constant_full_page_raster_05000_pixels_per_second"
     },
     {
-        "duration": "19.808581067567566",
+        "duration": "21.0",
         "name": "rendering.desktop/text_constant_full_page_raster_10000_pixels_per_second"
     },
     {
-        "duration": "16.666972959459454",
+        "duration": "18.0",
         "name": "rendering.desktop/text_constant_full_page_raster_15000_pixels_per_second"
     },
     {
-        "duration": "15.047608114864863",
+        "duration": "16.0",
         "name": "rendering.desktop/text_constant_full_page_raster_20000_pixels_per_second"
     },
     {
-        "duration": "13.516743189189185",
+        "duration": "15.0",
         "name": "rendering.desktop/text_constant_full_page_raster_30000_pixels_per_second"
     },
     {
-        "duration": "12.877716236486489",
+        "duration": "14.0",
         "name": "rendering.desktop/text_constant_full_page_raster_40000_pixels_per_second"
     },
     {
-        "duration": "12.335959466216215",
+        "duration": "13.0",
         "name": "rendering.desktop/text_constant_full_page_raster_50000_pixels_per_second"
     },
     {
-        "duration": "12.58914870945946",
+        "duration": "13.0",
         "name": "rendering.desktop/text_constant_full_page_raster_60000_pixels_per_second"
     },
     {
-        "duration": "11.68462166891892",
+        "duration": "13.0",
         "name": "rendering.desktop/text_constant_full_page_raster_75000_pixels_per_second"
     },
     {
-        "duration": "11.416162202702703",
+        "duration": "12.0",
         "name": "rendering.desktop/text_constant_full_page_raster_90000_pixels_per_second"
     },
     {
-        "duration": "19.79178378378379",
+        "duration": "20.0",
         "name": "rendering.desktop/text_hover_05000_pixels_per_second"
     },
     {
-        "duration": "17.201121675675672",
+        "duration": "19.0",
         "name": "rendering.desktop/text_hover_10000_pixels_per_second"
     },
     {
-        "duration": "14.721054000000002",
+        "duration": "16.0",
         "name": "rendering.desktop/text_hover_15000_pixels_per_second"
     },
     {
-        "duration": "13.377202729729728",
+        "duration": "14.0",
         "name": "rendering.desktop/text_hover_20000_pixels_per_second"
     },
     {
-        "duration": "11.969635047297293",
+        "duration": "13.0",
         "name": "rendering.desktop/text_hover_30000_pixels_per_second"
     },
     {
-        "duration": "11.293837891891894",
+        "duration": "12.0",
         "name": "rendering.desktop/text_hover_40000_pixels_per_second"
     },
     {
-        "duration": "10.92344593243244",
+        "duration": "12.0",
         "name": "rendering.desktop/text_hover_50000_pixels_per_second"
     },
     {
-        "duration": "10.592013520270271",
+        "duration": "12.0",
         "name": "rendering.desktop/text_hover_60000_pixels_per_second"
     },
     {
-        "duration": "10.378459466216217",
+        "duration": "11.0",
         "name": "rendering.desktop/text_hover_75000_pixels_per_second"
     },
     {
-        "duration": "10.215054013513514",
+        "duration": "11.0",
         "name": "rendering.desktop/text_hover_90000_pixels_per_second"
     },
     {
-        "duration": "18.392042857142854",
+        "duration": "20.0",
         "name": "rendering.desktop/touch_handler_scrolling"
     },
     {
-        "duration": "25.805744938775508",
+        "duration": "29.0",
         "name": "rendering.desktop/transform_transitions"
     },
     {
-        "duration": "20.99041835714286",
+        "duration": "23.0",
         "name": "rendering.desktop/transform_transitions_js_block"
     },
     {
-        "duration": "15.923585843434344",
-        "name": "rendering.desktop/twitter"
+        "duration": "20.0",
+        "name": "rendering.desktop/twitch_2018"
     },
     {
-        "duration": "3.4048243364864867",
+        "duration": "6.0",
+        "name": "rendering.desktop/twitch_pinch_2018"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/twitter_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/twitter_pinch"
     },
     {
-        "duration": "19.73749497979798",
-        "name": "rendering.desktop/weather.com"
+        "duration": "6.0",
+        "name": "rendering.desktop/twitter_pinch_2018"
     },
     {
-        "duration": "3.4737837824324322",
+        "duration": "4.0",
         "name": "rendering.desktop/weather_pinch"
     },
     {
-        "duration": "22.22325510204082",
+        "duration": "24.0",
         "name": "rendering.desktop/web_animation_value_type_color"
     },
     {
-        "duration": "22.554367326530606",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animation_value_type_length_3d"
     },
     {
-        "duration": "22.776071438775503",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animation_value_type_length_complex"
     },
     {
-        "duration": "22.66179593877551",
+        "duration": "24.0",
         "name": "rendering.desktop/web_animation_value_type_length_simple"
     },
     {
-        "duration": "23.72888772448981",
+        "duration": "26.0",
         "name": "rendering.desktop/web_animation_value_type_path"
     },
     {
-        "duration": "25.027612244897966",
+        "duration": "28.0",
         "name": "rendering.desktop/web_animation_value_type_shadow"
     },
     {
-        "duration": "22.083030591836728",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animation_value_type_transform_complex"
     },
     {
-        "duration": "22.058132642857146",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animation_value_type_transform_simple"
     },
     {
-        "duration": "22.424530581632656",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animations_many_keyframes"
     },
     {
-        "duration": "22.372724520408173",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animations_set_current_time"
     },
     {
-        "duration": "22.111806132653076",
+        "duration": "25.0",
         "name": "rendering.desktop/web_animations_simultaneous"
     },
     {
-        "duration": "24.110938775510206",
+        "duration": "27.0",
         "name": "rendering.desktop/web_animations_staggered_chaining"
     },
     {
-        "duration": "21.042408183673473",
+        "duration": "23.0",
         "name": "rendering.desktop/web_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "24.131163224489793",
+        "duration": "27.0",
         "name": "rendering.desktop/web_animations_staggered_triggering_page"
     },
     {
-        "duration": "20.867535313131317",
-        "name": "rendering.desktop/wikipedia"
+        "duration": "27.0",
+        "name": "rendering.desktop/wikipedia_2018"
     },
     {
-        "duration": "24.202080787878785",
-        "name": "rendering.desktop/wordpress"
+        "duration": "27.0",
+        "name": "rendering.desktop/wordpress_2018"
     },
     {
-        "duration": "13.9063132020202",
-        "name": "rendering.desktop/yahoo_answers"
+        "duration": "17.0",
+        "name": "rendering.desktop/yahoo_answers_2018"
     },
     {
-        "duration": "27.36668688888889",
-        "name": "rendering.desktop/yahoo_games"
-    },
-    {
-        "duration": "3.4052567567567564",
+        "duration": "4.0",
         "name": "rendering.desktop/yahoo_games_pinch"
     },
     {
-        "duration": "19.204212101010096",
-        "name": "rendering.desktop/yahoo_news"
+        "duration": "29.0",
+        "name": "rendering.desktop/yahoo_news_2018"
     },
     {
-        "duration": "3.4164054040540535",
+        "duration": "4.0",
         "name": "rendering.desktop/yahoo_news_pinch"
     },
     {
-        "duration": "22.487202030303028",
-        "name": "rendering.desktop/yahoo_sports"
+        "duration": "6.0",
+        "name": "rendering.desktop/yahoo_news_pinch_2018"
     },
     {
-        "duration": "3.3848513635135125",
+        "duration": "31.0",
+        "name": "rendering.desktop/yahoo_sports_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/yahoo_sports_pinch"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "rendering.desktop/youtube"
+        "duration": "6.0",
+        "name": "rendering.desktop/yahoo_sports_pinch_2018"
     },
     {
-        "duration": "1.9590675567567566",
+        "duration": "22.0",
+        "name": "rendering.desktop/youtube_2018"
+    },
+    {
+        "duration": "4.0",
         "name": "rendering.desktop/youtube_pinch"
     },
     {
-        "duration": "20.702314357142857",
+        "duration": "6.0",
+        "name": "rendering.desktop/youtube_pinch_2018"
+    },
+    {
+        "duration": "24.0",
         "name": "rendering.desktop/yuv_decoding"
     },
     {
-        "duration": "15.15833721511628",
-        "name": "scheduler.tough_scheduling_cases/raf"
-    },
-    {
-        "duration": "15.31183841414141",
-        "name": "scheduler.tough_scheduling_cases/raf.html"
-    },
-    {
-        "duration": "15.034860482558132",
-        "name": "scheduler.tough_scheduling_cases/raf_animation"
-    },
-    {
-        "duration": "15.171404075757577",
-        "name": "scheduler.tough_scheduling_cases/raf_animation.html"
-    },
-    {
-        "duration": "14.807779133720935",
-        "name": "scheduler.tough_scheduling_cases/raf_canvas"
-    },
-    {
-        "duration": "14.98819193434343",
-        "name": "scheduler.tough_scheduling_cases/raf_canvas.html"
-    },
-    {
-        "duration": "14.879592994186039",
-        "name": "scheduler.tough_scheduling_cases/raf_touch_animation"
-    },
-    {
-        "duration": "15.083070686868682",
-        "name": "scheduler.tough_scheduling_cases/raf_touch_animation.html"
-    },
-    {
-        "duration": "9.181262631313125",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js.html?heavy"
-    },
-    {
-        "duration": "9.228717186868687",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js.html?light"
-    },
-    {
-        "duration": "9.221727313131312",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js.html?medium"
-    },
-    {
-        "duration": "8.993337197674421",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js_heavy"
-    },
-    {
-        "duration": "8.918407005813952",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js_light"
-    },
-    {
-        "duration": "8.976790680232556",
-        "name": "scheduler.tough_scheduling_cases/second_batch_js_medium"
-    },
-    {
-        "duration": "25.921860453488375",
-        "name": "scheduler.tough_scheduling_cases/simple_text_page"
-    },
-    {
-        "duration": "31.042393898989896",
-        "name": "scheduler.tough_scheduling_cases/simple_text_page.html"
-    },
-    {
-        "duration": "10.525232575581398",
-        "name": "scheduler.tough_scheduling_cases/simple_touch_drag"
-    },
-    {
-        "duration": "10.714030252525257",
-        "name": "scheduler.tough_scheduling_cases/simple_touch_drag.html"
-    },
-    {
-        "duration": "13.158895395348843",
-        "name": "scheduler.tough_scheduling_cases/sync_scroll_offset"
-    },
-    {
-        "duration": "13.382323227272725",
-        "name": "scheduler.tough_scheduling_cases/sync_scroll_offset.html"
-    },
-    {
-        "duration": "14.508546488372092",
-        "name": "scheduler.tough_scheduling_cases/touch_handler_scrolling"
-    },
-    {
-        "duration": "14.925191853535352",
-        "name": "scheduler.tough_scheduling_cases/touch_handler_scrolling.html"
-    },
-    {
-        "duration": "19.795979777777774",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/Analog_Clock_SVG"
-    },
-    {
-        "duration": "19.78323232323232",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/Filter_Terrain_SVG"
-    },
-    {
-        "duration": "21.751252545454545",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/IE_PirateMark"
-    },
-    {
-        "duration": "41.54438378787879",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/MotionMark_Focus"
-    },
-    {
-        "duration": "19.681757515151514",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/analog_clock_svg"
-    },
-    {
-        "duration": "20.197171707070705",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/filter_terrain_svg"
-    },
-    {
-        "duration": "22.312787909090904",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/ie_pirate_mark"
-    },
-    {
-        "duration": "44.81907065656564",
-        "name": "smoothness.gpu_rasterization.tough_filters_cases/motion_mark_focus"
-    },
-    {
-        "duration": "51.9720706969697",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/GUIMark_Vector_Chart_Test"
-    },
-    {
-        "duration": "29.101070707070715",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/IE_Chalkboard"
-    },
-    {
-        "duration": "20.926070777777785",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/MotionMark_Canvas_Fill_Shapes"
-    },
-    {
-        "duration": "20.384282818181816",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/MotionMark_Canvas_Stroke_Shapes"
-    },
-    {
-        "duration": "52.746656565656565",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/guimark_vector_chart"
-    },
-    {
-        "duration": "29.01680805050505",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/ie_chalkboard"
-    },
-    {
-        "duration": "20.63228283838384",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/motion_mark_canvas_fill_shapes"
-    },
-    {
-        "duration": "20.179828292929287",
-        "name": "smoothness.gpu_rasterization.tough_path_rendering_cases/motion_mark_canvas_stroke_shapes"
-    },
-    {
-        "duration": "15.131030378787882",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.56143430808081",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.14886865656566",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.244898974747475",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.16179801515152",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.630282818181815",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.26740403030303",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.999141434343434",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.813020227272727",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.673272720202023",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/canvas_90000_pixels_per_second"
-    },
-    {
-        "duration": "30.59284860606062",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.88858582828283",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_10000_pixels_per_second"
-    },
-    {
-        "duration": "11.81005052020202",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_15000_pixels_per_second"
-    },
-    {
-        "duration": "10.872798010101011",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.478525227272726",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.897767702020204",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.042797954545454",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.830888904040403",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.550494941414142",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.431555533333336",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_90000_pixels_per_second"
-    },
-    {
-        "duration": "15.589919191919195",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.418969676767679",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.280929227272722",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.269858580808082",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.318515111111115",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.928242409090911",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_40000_pixels_per_second"
-    },
-    {
-        "duration": "10.569131398989896",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.399424242424246",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_60000_pixels_per_second"
-    },
-    {
-        "duration": "9.649555500000002",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_75000_pixels_per_second"
-    },
-    {
-        "duration": "9.578818176767674",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_constant_full_page_raster_90000_pixels_per_second"
-    },
-    {
-        "duration": "15.15427264646465",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_05000_pixels_per_second"
-    },
-    {
-        "duration": "13.536212106060606",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_10000_pixels_per_second"
-    },
-    {
-        "duration": "11.618383838383835",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_15000_pixels_per_second"
-    },
-    {
-        "duration": "10.623737333333333",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_20000_pixels_per_second"
-    },
-    {
-        "duration": "9.625353520202022",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.088282823232323",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_40000_pixels_per_second"
-    },
-    {
-        "duration": "8.84143434848485",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.61992928787879",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.38473734848485",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.279404068686873",
-        "name": "smoothness.gpu_rasterization.tough_scrolling_cases/text_hover_90000_pixels_per_second"
-    },
-    {
-        "duration": "38.04753491860465",
-        "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases/yuv_decoding"
-    },
-    {
-        "duration": "33.75913132323232",
-        "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases/yuv_decoding.html"
-    },
-    {
-        "duration": "40.28665120930233",
-        "name": "smoothness.image_decoding_cases/yuv_decoding"
-    },
-    {
-        "duration": "29.01557576767676",
-        "name": "smoothness.image_decoding_cases/yuv_decoding.html"
-    },
-    {
-        "duration": "27.1506969090909",
-        "name": "smoothness.key_desktop_move_cases/Maps"
-    },
-    {
-        "duration": "24.607070717171723",
-        "name": "smoothness.key_desktop_move_cases/maps_move"
-    },
-    {
-        "duration": "27.847868666666667",
-        "name": "smoothness.maps/maps_perf_test"
-    },
-    {
-        "duration": "17.11933334343434",
-        "name": "smoothness.top_25_smooth/blogspot"
-    },
-    {
-        "duration": "12.75833332323233",
-        "name": "smoothness.top_25_smooth/booking.com"
-    },
-    {
-        "duration": "0.0010000864333333333",
-        "name": "smoothness.top_25_smooth/cnn"
-    },
-    {
-        "duration": "10.977151525252527",
-        "name": "smoothness.top_25_smooth/ebay"
-    },
-    {
-        "duration": "14.301929267676769",
-        "name": "smoothness.top_25_smooth/espn"
-    },
-    {
-        "duration": "13.018010116161616",
-        "name": "smoothness.top_25_smooth/facebook"
-    },
-    {
-        "duration": "27.640929323232317",
-        "name": "smoothness.top_25_smooth/gmail"
-    },
-    {
-        "duration": "0.0010000069666666665",
-        "name": "smoothness.top_25_smooth/google_calendar"
-    },
-    {
-        "duration": "0.0010001659",
-        "name": "smoothness.top_25_smooth/google_docs"
-    },
-    {
-        "duration": "9.999275E-4",
-        "name": "smoothness.top_25_smooth/google_image_search"
-    },
-    {
-        "duration": "10.507616191919194",
-        "name": "smoothness.top_25_smooth/google_web_search"
-    },
-    {
-        "duration": "13.958949494949497",
-        "name": "smoothness.top_25_smooth/linkedin"
-    },
-    {
-        "duration": "16.310515161616166",
-        "name": "smoothness.top_25_smooth/pinterest"
-    },
-    {
-        "duration": "20.70723233333334",
-        "name": "smoothness.top_25_smooth/techcrunch"
-    },
-    {
-        "duration": "15.03598987878789",
-        "name": "smoothness.top_25_smooth/twitter"
-    },
-    {
-        "duration": "12.585848464646466",
-        "name": "smoothness.top_25_smooth/weather.com"
-    },
-    {
-        "duration": "17.645787878787885",
-        "name": "smoothness.top_25_smooth/wikipedia"
-    },
-    {
-        "duration": "16.997292959595967",
-        "name": "smoothness.top_25_smooth/wordpress"
-    },
-    {
-        "duration": "11.186515176767678",
-        "name": "smoothness.top_25_smooth/yahoo_answers"
-    },
-    {
-        "duration": "18.221848464646463",
-        "name": "smoothness.top_25_smooth/yahoo_games"
-    },
-    {
-        "duration": "12.568686863636373",
-        "name": "smoothness.top_25_smooth/yahoo_news"
-    },
-    {
-        "duration": "13.60135346969697",
-        "name": "smoothness.top_25_smooth/yahoo_sports"
-    },
-    {
-        "duration": "27.779818151515148",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CICAgICQ15a9NxDIARjIASgBMghBC1XuTk8ezw.swiffy72.html"
-    },
-    {
-        "duration": "20.038121222222227",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CICAgIDQ2Pb-MxCsAhj6ASgBMgi5DLoSO0gPbQ.swiffy72.html"
-    },
-    {
-        "duration": "20.01881821212121",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CICAgKCN39CopQEQoAEY2AQoATIID59gK5hjjIg.swiffy72.html"
-    },
-    {
-        "duration": "20.017929262626264",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CICAgKCNj4HgyAEQeBjYBCgBMgjQpPkOjyWNdw.1.swiffy72.html"
-    },
-    {
-        "duration": "19.9578686969697",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CICAgMDOrcnRGRB4GNgEKAEyCP_ZBSfwUFsj.swiffy72.html"
-    },
-    {
-        "duration": "20.21655556565656",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/CNP2xe_LmqPEKBCsAhj6ASgBMggnyMqth81h8Q.swiffy72.html"
-    },
-    {
-        "duration": "20.237212191919188",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/clip-paths-CICAgMDO7Ye9-gEQ2AUYWigBMgjZxDii6aoK9w.swiffy72.html"
-    },
-    {
-        "duration": "20.021727272727272",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/clip-paths-CILZhLqO_-27bxB4GNgEKAEyCC46kMLBXnMT.swiffy72.html"
-    },
-    {
-        "duration": "20.125565686868683",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/filters-CNLa0t2T47qJ_wEQoAEY2AQoATIIFaIdc7VMBr4.swiffy72.html"
-    },
-    {
-        "duration": "20.035535333333332",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/shapes-CICAgMDO7cfIzwEQ1AMYPCgBMghqY8tqyRCArQ.swiffy72.html"
-    },
-    {
-        "duration": "20.25348484848485",
-        "name": "smoothness.tough_ad_cases/http://localhost:8000/shapes-CK7ptO3F8bi2KxDQAhiYAigBMgij6QBQtD2gyA.swiffy72.html"
-    },
-    {
-        "duration": "18.995739562500003",
-        "name": "smoothness.tough_animation_cases/balls_css_key_frame_animations"
-    },
-    {
-        "duration": "19.07282293749999",
-        "name": "smoothness.tough_animation_cases/balls_css_key_frame_animations_composited_transform"
-    },
-    {
-        "duration": "18.985282787878788",
-        "name": "smoothness.tough_animation_cases/balls_css_keyframe_animations.html"
-    },
-    {
-        "duration": "19.10113132323232",
-        "name": "smoothness.tough_animation_cases/balls_css_keyframe_animations_composited_transform.html"
-    },
-    {
-        "duration": "20.622604156249995",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_2_properties"
-    },
-    {
-        "duration": "20.401262616161617",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_2_properties.html"
-    },
-    {
-        "duration": "21.073812510416662",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_40_properties"
-    },
-    {
-        "duration": "20.43532321212121",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_40_properties.html"
-    },
-    {
-        "duration": "20.624104187500006",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_all_properties"
-    },
-    {
-        "duration": "20.497686858585855",
-        "name": "smoothness.tough_animation_cases/balls_css_transition_all_properties.html"
-    },
-    {
-        "duration": "18.86768755208333",
-        "name": "smoothness.tough_animation_cases/balls_javascript_canvas"
-    },
-    {
-        "duration": "19.023666616161623",
-        "name": "smoothness.tough_animation_cases/balls_javascript_canvas.html"
-    },
-    {
-        "duration": "19.211802093750006",
-        "name": "smoothness.tough_animation_cases/balls_javascript_css"
-    },
-    {
-        "duration": "18.6277071010101",
-        "name": "smoothness.tough_animation_cases/balls_javascript_css.html"
-    },
-    {
-        "duration": "34.084863136842124",
-        "name": "smoothness.tough_animation_cases/balls_svg_animations"
-    },
-    {
-        "duration": "36.266121232323215",
-        "name": "smoothness.tough_animation_cases/balls_svg_animations.html"
-    },
-    {
-        "duration": "19.251333333333335",
-        "name": "smoothness.tough_animation_cases/compositor_heavy_animation"
-    },
-    {
-        "duration": "19.60129290909091",
-        "name": "smoothness.tough_animation_cases/compositor_heavy_animation.html?N=0200"
-    },
-    {
-        "duration": "18.196791708333333",
-        "name": "smoothness.tough_animation_cases/css_animations_many_keyframes"
-    },
-    {
-        "duration": "18.194101040404046",
-        "name": "smoothness.tough_animation_cases/css_animations_many_keyframes.html?N=0316"
-    },
-    {
-        "duration": "18.63116163636364",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "18.246262595959593",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "18.311121222222223",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "18.330899030303023",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "18.268979135416668",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_inline_style"
-    },
-    {
-        "duration": "18.691406281250003",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_new_element"
-    },
-    {
-        "duration": "18.238843739583338",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_style_element"
-    },
-    {
-        "duration": "18.312645822916668",
-        "name": "smoothness.tough_animation_cases/css_animations_simultaneous_updating_class"
-    },
-    {
-        "duration": "21.245686878787886",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_chaining_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "19.75654544444445",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_chaining_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "19.803212141414143",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_chaining_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "19.86957578787879",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_chaining_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "18.382333302083335",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_infinite_iterations"
-    },
-    {
-        "duration": "17.866676777777776",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_infinite_iterations.html?N=0316"
-    },
-    {
-        "duration": "19.611937479166674",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_inline_style"
-    },
-    {
-        "duration": "20.707750020833334",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_new_element"
-    },
-    {
-        "duration": "20.166864531250003",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_style_element"
-    },
-    {
-        "duration": "20.309242393939392",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_triggering_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "19.252131323232323",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_triggering_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "19.578141464646457",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_triggering_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "19.645373787878782",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_triggering_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "19.586749989583343",
-        "name": "smoothness.tough_animation_cases/css_animations_staggered_updating_class"
-    },
-    {
-        "duration": "19.620125031249994",
-        "name": "smoothness.tough_animation_cases/css_animations_triggered_inline_style"
-    },
-    {
-        "duration": "20.291874968749994",
-        "name": "smoothness.tough_animation_cases/css_animations_triggered_new_element"
-    },
-    {
-        "duration": "19.25103125",
-        "name": "smoothness.tough_animation_cases/css_animations_triggered_style_element"
-    },
-    {
-        "duration": "19.981968791666667",
-        "name": "smoothness.tough_animation_cases/css_animations_triggered_updating_class"
-    },
-    {
-        "duration": "18.430041645833338",
-        "name": "smoothness.tough_animation_cases/css_transitions_inline_style"
-    },
-    {
-        "duration": "19.208312489583328",
-        "name": "smoothness.tough_animation_cases/css_transitions_new_element"
-    },
-    {
-        "duration": "19.17046462626263",
-        "name": "smoothness.tough_animation_cases/css_transitions_simultaneous_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "18.457161616161617",
-        "name": "smoothness.tough_animation_cases/css_transitions_simultaneous_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "18.358232353535353",
-        "name": "smoothness.tough_animation_cases/css_transitions_simultaneous_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "19.094171737373735",
-        "name": "smoothness.tough_animation_cases/css_transitions_simultaneous_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "18.72763637373738",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_chaining_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "19.171090858585867",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_chaining_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "18.470212111111106",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_chaining_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "18.443808060606063",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_chaining_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "18.98592709375",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_inline_style"
-    },
-    {
-        "duration": "18.699604145833334",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_new_element"
-    },
-    {
-        "duration": "18.505510416666667",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_style_element"
-    },
-    {
-        "duration": "19.13276768686869",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_triggering_by_inserting_new_element.html?N=0316"
-    },
-    {
-        "duration": "19.08491921212121",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_triggering_by_inserting_style_element.html?N=0316"
-    },
-    {
-        "duration": "19.090141414141424",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_triggering_by_updating_class.html?N=0316"
-    },
-    {
-        "duration": "19.13597980808081",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_triggering_by_updating_inline_style.html?N=0316"
-    },
-    {
-        "duration": "18.45888540625",
-        "name": "smoothness.tough_animation_cases/css_transitions_staggered_updating_class"
-    },
-    {
-        "duration": "18.38427084375",
-        "name": "smoothness.tough_animation_cases/css_transitions_style_element"
-    },
-    {
-        "duration": "19.10522916666668",
-        "name": "smoothness.tough_animation_cases/css_transitions_triggered_inline_style"
-    },
-    {
-        "duration": "19.587666635416667",
-        "name": "smoothness.tough_animation_cases/css_transitions_triggered_new_element"
-    },
-    {
-        "duration": "19.055364520833336",
-        "name": "smoothness.tough_animation_cases/css_transitions_triggered_style_element"
-    },
-    {
-        "duration": "19.098031281249998",
-        "name": "smoothness.tough_animation_cases/css_transitions_triggered_updating_class"
-    },
-    {
-        "duration": "18.81317707291667",
-        "name": "smoothness.tough_animation_cases/css_transitions_updating_class"
-    },
-    {
-        "duration": "17.882895802083336",
-        "name": "smoothness.tough_animation_cases/css_value_type_color"
-    },
-    {
-        "duration": "18.851525242424238",
-        "name": "smoothness.tough_animation_cases/css_value_type_color.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "17.91474749494948",
-        "name": "smoothness.tough_animation_cases/css_value_type_color.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.352031249999996",
-        "name": "smoothness.tough_animation_cases/css_value_type_filter"
-    },
-    {
-        "duration": "18.871242424242425",
-        "name": "smoothness.tough_animation_cases/css_value_type_filter.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.141958302083335",
-        "name": "smoothness.tough_animation_cases/css_value_type_length"
-    },
-    {
-        "duration": "18.14075756565656",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_3d.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.116585888888885",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_3d.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.307833364583328",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_complex"
-    },
-    {
-        "duration": "18.34028282828283",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_complex.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.367717171717175",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_complex.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.294760447916666",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_simple"
-    },
-    {
-        "duration": "18.33121211111111",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_simple.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.371161626262616",
-        "name": "smoothness.tough_animation_cases/css_value_type_length_simple.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.535250000000005",
-        "name": "smoothness.tough_animation_cases/css_value_type_path"
-    },
-    {
-        "duration": "18.657717171717174",
-        "name": "smoothness.tough_animation_cases/css_value_type_path.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.624141404040405",
-        "name": "smoothness.tough_animation_cases/css_value_type_path.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "19.706625010416673",
-        "name": "smoothness.tough_animation_cases/css_value_type_shadow"
-    },
-    {
-        "duration": "19.307636383838375",
-        "name": "smoothness.tough_animation_cases/css_value_type_shadow.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "19.312888878787888",
-        "name": "smoothness.tough_animation_cases/css_value_type_shadow.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.157479145833324",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_complex"
-    },
-    {
-        "duration": "18.156878808080815",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_complex.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.171424272727275",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_complex.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "18.445604156250003",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_simple"
-    },
-    {
-        "duration": "18.214363626262628",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_simple.html?api=css_animations&N=0316"
-    },
-    {
-        "duration": "18.497404090909093",
-        "name": "smoothness.tough_animation_cases/css_value_type_transform_simple.html?api=web_animations&N=0316"
-    },
-    {
-        "duration": "17.814864572916672",
-        "name": "smoothness.tough_animation_cases/keyframed_animations"
-    },
-    {
-        "duration": "17.770919212121214",
-        "name": "smoothness.tough_animation_cases/keyframed_animations.html"
-    },
-    {
-        "duration": "18.126718760416672",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_difference"
-    },
-    {
-        "duration": "18.123292959595968",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_difference.html"
-    },
-    {
-        "duration": "18.138885447916664",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_hue"
-    },
-    {
-        "duration": "18.112222212121207",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_hue.html"
-    },
-    {
-        "duration": "18.936708364583332",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_propagating_isolation"
-    },
-    {
-        "duration": "18.07853129166666",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_screen"
-    },
-    {
-        "duration": "18.513646474747482",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_animation_screen.html"
-    },
-    {
-        "duration": "18.41735356565656",
-        "name": "smoothness.tough_animation_cases/mix_blend_mode_propagating_isolation.html"
-    },
-    {
-        "duration": "29.211747454545442",
-        "name": "smoothness.tough_animation_cases/overlay_background_color_css_transitions.html"
-    },
-    {
-        "duration": "30.778989604166668",
-        "name": "smoothness.tough_animation_cases/overlay_background_color_css_transitions_page"
-    },
-    {
-        "duration": "9.999751799999999E-4",
-        "name": "smoothness.tough_animation_cases/robohornetpro"
-    },
-    {
-        "duration": "17.711919171717174",
-        "name": "smoothness.tough_animation_cases/transform_transition_js_block.html"
-    },
-    {
-        "duration": "17.865125052083336",
-        "name": "smoothness.tough_animation_cases/transform_transitions"
-    },
-    {
-        "duration": "17.92824241414142",
-        "name": "smoothness.tough_animation_cases/transform_transitions.html"
-    },
-    {
-        "duration": "17.659677052083335",
-        "name": "smoothness.tough_animation_cases/transform_transitions_js_block"
-    },
-    {
-        "duration": "17.881927083333334",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_color"
-    },
-    {
-        "duration": "18.113531229166664",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_length_3d"
-    },
-    {
-        "duration": "18.301187520833327",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_length_complex"
-    },
-    {
-        "duration": "18.336427062499997",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_length_simple"
-    },
-    {
-        "duration": "18.919083343750003",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_path"
-    },
-    {
-        "duration": "19.342729145833335",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_shadow"
-    },
-    {
-        "duration": "18.19162503125",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_transform_complex"
-    },
-    {
-        "duration": "18.532947906249998",
-        "name": "smoothness.tough_animation_cases/web_animation_value_type_transform_simple"
-    },
-    {
-        "duration": "19.584781291666665",
-        "name": "smoothness.tough_animation_cases/web_animations_many_keyframes"
-    },
-    {
-        "duration": "18.753343444444443",
-        "name": "smoothness.tough_animation_cases/web_animations_many_keyframes.html?N=0316"
-    },
-    {
-        "duration": "18.605364572916667",
-        "name": "smoothness.tough_animation_cases/web_animations_set_current_time"
-    },
-    {
-        "duration": "18.16735348484848",
-        "name": "smoothness.tough_animation_cases/web_animations_set_current_time_in_raf.html?N=0316"
-    },
-    {
-        "duration": "19.416145781250005",
-        "name": "smoothness.tough_animation_cases/web_animations_simultaneous"
-    },
-    {
-        "duration": "18.401323232323236",
-        "name": "smoothness.tough_animation_cases/web_animations_simultaneous.html?N=0316"
-    },
-    {
-        "duration": "19.539427093750003",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_chaining"
-    },
-    {
-        "duration": "19.539565676767673",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_chaining.html?N=0316"
-    },
-    {
-        "duration": "17.936749999999996",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_infinite_iterations"
-    },
-    {
-        "duration": "17.872737363636364",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_infinite_iterations.html?N=0316"
-    },
-    {
-        "duration": "19.639808060606057",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_triggering.html?N=0316"
-    },
-    {
-        "duration": "19.546645864583326",
-        "name": "smoothness.tough_animation_cases/web_animations_staggered_triggering_page"
-    },
-    {
-        "duration": "14.892676767676765",
-        "name": "smoothness.tough_canvas_cases/../../../chrome/test/data/perf/canvas_bench/many_images.html"
-    },
-    {
-        "duration": "13.032020181818181",
-        "name": "smoothness.tough_canvas_cases/bouncing_balls_15"
-    },
-    {
-        "duration": "14.014707045454545",
-        "name": "smoothness.tough_canvas_cases/bouncing_balls_shadow"
-    },
-    {
-        "duration": "13.722242434343437",
-        "name": "smoothness.tough_canvas_cases/bouncing_clipped_rectangles"
-    },
-    {
-        "duration": "13.715616181818184",
-        "name": "smoothness.tough_canvas_cases/bouncing_gradient_circles"
-    },
-    {
-        "duration": "12.263353550505055",
-        "name": "smoothness.tough_canvas_cases/bouncing_png_images"
-    },
-    {
-        "duration": "19.126242414141416",
-        "name": "smoothness.tough_canvas_cases/bouncing_svg_images"
-    },
-    {
-        "duration": "14.204727262626262",
-        "name": "smoothness.tough_canvas_cases/canvas_animation_no_clear"
-    },
-    {
-        "duration": "13.648717186868682",
-        "name": "smoothness.tough_canvas_cases/canvas_arcs"
-    },
-    {
-        "duration": "13.0385960050505",
-        "name": "smoothness.tough_canvas_cases/canvas_font_cycler"
-    },
-    {
-        "duration": "12.954828252525251",
-        "name": "smoothness.tough_canvas_cases/canvas_lines"
-    },
-    {
-        "duration": "12.981747449494945",
-        "name": "smoothness.tough_canvas_cases/canvas_to_blob"
-    },
-    {
-        "duration": "13.81446464646465",
-        "name": "smoothness.tough_canvas_cases/chip_tune"
-    },
-    {
-        "duration": "13.592616106060598",
-        "name": "smoothness.tough_canvas_cases/crafty_mind"
-    },
-    {
-        "duration": "14.312555565656565",
-        "name": "smoothness.tough_canvas_cases/effect_games"
-    },
-    {
-        "duration": "13.661171696969694",
-        "name": "smoothness.tough_canvas_cases/fill_shapes"
-    },
-    {
-        "duration": "21.97107068686869",
-        "name": "smoothness.tough_canvas_cases/geo_apis"
-    },
-    {
-        "duration": "13.620181873737378",
-        "name": "smoothness.tough_canvas_cases/hakim"
-    },
-    {
-        "duration": "21.673343429292927",
-        "name": "smoothness.tough_canvas_cases/http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM"
-    },
-    {
-        "duration": "13.790323222222218",
-        "name": "smoothness.tough_canvas_cases/http://hakim.se/experiments/html5/magnetic/02/"
-    },
-    {
-        "duration": "13.672020207070709",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Graphics/TweetMap/Default.html"
-    },
-    {
-        "duration": "14.644050409090902",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Graphics/VideoCity/Default.html"
-    },
-    {
-        "duration": "13.928010080808086",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Graphics/WorkerFountains/Default.html"
-    },
-    {
-        "duration": "14.03984847979799",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Performance/AsteroidBelt/Default.html"
-    },
-    {
-        "duration": "14.388626277777773",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Performance/FishIETank/Default.html"
-    },
-    {
-        "duration": "14.050181828282827",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Performance/LetItSnow/"
-    },
-    {
-        "duration": "13.589656545454547",
-        "name": "smoothness.tough_canvas_cases/http://ie.microsoft.com/testdrive/Performance/SpeedReading/Default.html"
-    },
-    {
-        "duration": "14.830646479797982",
-        "name": "smoothness.tough_canvas_cases/http://jarrodoverson.com/static/demos/particleSystem/"
-    },
-    {
-        "duration": "13.506060545454552",
-        "name": "smoothness.tough_canvas_cases/http://mix10k.visitmix.com/Entry/Details/169"
-    },
-    {
-        "duration": "13.030030252525256",
-        "name": "smoothness.tough_canvas_cases/http://runway.countlessprojects.com/prototype/performance_test.html"
-    },
-    {
-        "duration": "13.271333348484845",
-        "name": "smoothness.tough_canvas_cases/http://spielzeugz.de/html5/liquid-particles.html"
-    },
-    {
-        "duration": "13.991646489898987",
-        "name": "smoothness.tough_canvas_cases/http://themaninblue.com/experiment/AnimationBenchmark/canvas/"
-    },
-    {
-        "duration": "13.987404055555553",
-        "name": "smoothness.tough_canvas_cases/http://www.chiptune.com/starfield/starfield.html"
-    },
-    {
-        "duration": "13.795262611111111",
-        "name": "smoothness.tough_canvas_cases/http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html"
-    },
-    {
-        "duration": "14.554939444444447",
-        "name": "smoothness.tough_canvas_cases/http://www.effectgames.com/demos/canvascycle/"
-    },
-    {
-        "duration": "13.672161651515143",
-        "name": "smoothness.tough_canvas_cases/http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html"
-    },
-    {
-        "duration": "13.39483832828283",
-        "name": "smoothness.tough_canvas_cases/http://www.megidish.net/awjs/"
-    },
-    {
-        "duration": "13.659070752525253",
-        "name": "smoothness.tough_canvas_cases/http://www.smashcat.org/av/canvas_test/"
-    },
-    {
-        "duration": "14.654686888888882",
-        "name": "smoothness.tough_canvas_cases/jarro_doverson"
-    },
-    {
-        "duration": "13.519656565656557",
-        "name": "smoothness.tough_canvas_cases/kevs_3d"
-    },
-    {
-        "duration": "13.875070676767676",
-        "name": "smoothness.tough_canvas_cases/man_in_blue"
-    },
-    {
-        "duration": "14.753404030303027",
-        "name": "smoothness.tough_canvas_cases/many_images"
-    },
-    {
-        "duration": "13.235101015151516",
-        "name": "smoothness.tough_canvas_cases/megi_dish"
-    },
-    {
-        "duration": "13.945575752525258",
-        "name": "smoothness.tough_canvas_cases/microsoft_asteroid_belt"
-    },
-    {
-        "duration": "13.882080727272733",
-        "name": "smoothness.tough_canvas_cases/microsoft_fish_ie_tank"
-    },
-    {
-        "duration": "13.864191944444444",
-        "name": "smoothness.tough_canvas_cases/microsoft_snow"
-    },
-    {
-        "duration": "13.368444454545452",
-        "name": "smoothness.tough_canvas_cases/microsoft_speed_reading"
-    },
-    {
-        "duration": "13.469030272727272",
-        "name": "smoothness.tough_canvas_cases/microsoft_tweet_map"
-    },
-    {
-        "duration": "14.487484823232322",
-        "name": "smoothness.tough_canvas_cases/microsoft_video_city"
-    },
-    {
-        "duration": "13.82361620707071",
-        "name": "smoothness.tough_canvas_cases/microsoft_worker_fountains"
-    },
-    {
-        "duration": "13.387747494949497",
-        "name": "smoothness.tough_canvas_cases/mix_10k"
-    },
-    {
-        "duration": "13.637989909090907",
-        "name": "smoothness.tough_canvas_cases/put_get_image_data"
-    },
-    {
-        "duration": "12.897272752525247",
-        "name": "smoothness.tough_canvas_cases/runway"
-    },
-    {
-        "duration": "13.57649502020203",
-        "name": "smoothness.tough_canvas_cases/smash_cat"
-    },
-    {
-        "duration": "13.635020156565654",
-        "name": "smoothness.tough_canvas_cases/spielzeugz"
-    },
-    {
-        "duration": "14.029888848484836",
-        "name": "smoothness.tough_canvas_cases/stroke_shapes"
-    },
-    {
-        "duration": "14.316868702020203",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/canvas-animation-no-clear.html"
-    },
-    {
-        "duration": "13.108666666666663",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/canvas-font-cycler.html"
-    },
-    {
-        "duration": "14.26334342929293",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/canvas2d_balls_common/bouncing_balls.html?ball=image_with_shadow&back=image"
-    },
-    {
-        "duration": "13.128424222222216",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/canvas2d_balls_common/bouncing_balls.html?ball=text&back=white&ball_count=15"
-    },
-    {
-        "duration": "13.124646525252526",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/canvas_toBlob.html"
-    },
-    {
-        "duration": "13.93056563636364",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/bouncing_clipped_rectangles.html"
-    },
-    {
-        "duration": "13.79218181313132",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/bouncing_gradient_circles.html"
-    },
-    {
-        "duration": "12.822212131313137",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/bouncing_png_images.html"
-    },
-    {
-        "duration": "20.561161606060615",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/bouncing_svg_images.html"
-    },
-    {
-        "duration": "13.860545414141415",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/canvas_arcs.html"
-    },
-    {
-        "duration": "13.07291912626263",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/canvas_lines.html"
-    },
-    {
-        "duration": "13.70785862121212",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/fill_shapes.html"
-    },
-    {
-        "duration": "13.70504037878788",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/put_get_image_data.html"
-    },
-    {
-        "duration": "14.17184845959596",
-        "name": "smoothness.tough_canvas_cases/tough_canvas_cases/rendering_throughput/stroke_shapes.html"
-    },
-    {
-        "duration": "20.041484828282833",
-        "name": "smoothness.tough_filters_cases/Analog_Clock_SVG"
-    },
-    {
-        "duration": "20.04446463636364",
-        "name": "smoothness.tough_filters_cases/Filter_Terrain_SVG"
-    },
-    {
-        "duration": "22.60951514141414",
-        "name": "smoothness.tough_filters_cases/IE_PirateMark"
-    },
-    {
-        "duration": "31.47287877777778",
-        "name": "smoothness.tough_filters_cases/MotionMark_Focus"
-    },
-    {
-        "duration": "19.892101050505044",
-        "name": "smoothness.tough_filters_cases/analog_clock_svg"
-    },
-    {
-        "duration": "19.93245452525253",
-        "name": "smoothness.tough_filters_cases/filter_terrain_svg"
-    },
-    {
-        "duration": "22.09837376767677",
-        "name": "smoothness.tough_filters_cases/ie_pirate_mark"
-    },
-    {
-        "duration": "35.45863639393937",
-        "name": "smoothness.tough_filters_cases/motion_mark_focus"
-    },
-    {
-        "duration": "16.984195109756097",
-        "name": "smoothness.tough_image_decode_cases/cats_unscaled"
-    },
-    {
-        "duration": "10.023646371951218",
-        "name": "smoothness.tough_image_decode_cases/cats_viewport_width"
-    },
-    {
-        "duration": "17.949525313131318",
-        "name": "smoothness.tough_image_decode_cases/http://localhost:9000/cats-unscaled.html"
-    },
-    {
-        "duration": "10.156555525252525",
-        "name": "smoothness.tough_image_decode_cases/http://localhost:9000/cats-viewport-width.html"
-    },
-    {
-        "duration": "31.122909101010105",
-        "name": "smoothness.tough_path_rendering_cases/GUIMark_Vector_Chart_Test"
-    },
-    {
-        "duration": "28.501939393939395",
-        "name": "smoothness.tough_path_rendering_cases/IE_Chalkboard"
-    },
-    {
-        "duration": "19.635505060606054",
-        "name": "smoothness.tough_path_rendering_cases/MotionMark_Canvas_Fill_Shapes"
-    },
-    {
-        "duration": "19.80110101010101",
-        "name": "smoothness.tough_path_rendering_cases/MotionMark_Canvas_Stroke_Shapes"
-    },
-    {
-        "duration": "29.954878808080817",
-        "name": "smoothness.tough_path_rendering_cases/guimark_vector_chart"
-    },
-    {
-        "duration": "28.844555575757568",
-        "name": "smoothness.tough_path_rendering_cases/ie_chalkboard"
-    },
-    {
-        "duration": "19.630232292929293",
-        "name": "smoothness.tough_path_rendering_cases/motion_mark_canvas_fill_shapes"
-    },
-    {
-        "duration": "20.12891921212121",
-        "name": "smoothness.tough_path_rendering_cases/motion_mark_canvas_stroke_shapes"
-    },
-    {
-        "duration": "15.180777787878789",
-        "name": "smoothness.tough_scrolling_cases/canvas_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.441070717171714",
-        "name": "smoothness.tough_scrolling_cases/canvas_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.058010116161618",
-        "name": "smoothness.tough_scrolling_cases/canvas_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.204575828282824",
-        "name": "smoothness.tough_scrolling_cases/canvas_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.155232348484848",
-        "name": "smoothness.tough_scrolling_cases/canvas_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.644656570707069",
-        "name": "smoothness.tough_scrolling_cases/canvas_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.331323252525253",
-        "name": "smoothness.tough_scrolling_cases/canvas_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.060535383838387",
-        "name": "smoothness.tough_scrolling_cases/canvas_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.858262641414147",
-        "name": "smoothness.tough_scrolling_cases/canvas_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.705191974747473",
-        "name": "smoothness.tough_scrolling_cases/canvas_90000_pixels_per_second"
-    },
-    {
-        "duration": "24.019505095959598",
-        "name": "smoothness.tough_scrolling_cases/text_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.298757530303027",
-        "name": "smoothness.tough_scrolling_cases/text_10000_pixels_per_second"
-    },
-    {
-        "duration": "11.874373686868683",
-        "name": "smoothness.tough_scrolling_cases/text_15000_pixels_per_second"
-    },
-    {
-        "duration": "10.94608081313131",
-        "name": "smoothness.tough_scrolling_cases/text_20000_pixels_per_second"
-    },
-    {
-        "duration": "9.978000010101013",
-        "name": "smoothness.tough_scrolling_cases/text_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.453595989898991",
-        "name": "smoothness.tough_scrolling_cases/text_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.029161595959591",
-        "name": "smoothness.tough_scrolling_cases/text_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.890696934343437",
-        "name": "smoothness.tough_scrolling_cases/text_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.645333313131315",
-        "name": "smoothness.tough_scrolling_cases/text_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.589212116161614",
-        "name": "smoothness.tough_scrolling_cases/text_90000_pixels_per_second"
-    },
-    {
-        "duration": "15.68423229797979",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.530595974747476",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.455717222222216",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.375646449494948",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.343777782828282",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.986505065656562",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.666070712121211",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.342262631313131",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_60000_pixels_per_second"
-    },
-    {
-        "duration": "9.122434373737375",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_75000_pixels_per_second"
-    },
-    {
-        "duration": "9.015292873737373",
-        "name": "smoothness.tough_scrolling_cases/text_constant_full_page_raster_90000_pixels_per_second"
-    },
-    {
-        "duration": "14.869282883838395",
-        "name": "smoothness.tough_scrolling_cases/text_hover_05000_pixels_per_second"
-    },
-    {
-        "duration": "13.661353484848481",
-        "name": "smoothness.tough_scrolling_cases/text_hover_10000_pixels_per_second"
-    },
-    {
-        "duration": "11.692808101010097",
-        "name": "smoothness.tough_scrolling_cases/text_hover_15000_pixels_per_second"
-    },
-    {
-        "duration": "10.661373737373735",
-        "name": "smoothness.tough_scrolling_cases/text_hover_20000_pixels_per_second"
-    },
-    {
-        "duration": "9.761899015151517",
-        "name": "smoothness.tough_scrolling_cases/text_hover_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.131212075757578",
-        "name": "smoothness.tough_scrolling_cases/text_hover_40000_pixels_per_second"
-    },
-    {
-        "duration": "8.879999959595958",
-        "name": "smoothness.tough_scrolling_cases/text_hover_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.706353547474746",
-        "name": "smoothness.tough_scrolling_cases/text_hover_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.438535354545454",
-        "name": "smoothness.tough_scrolling_cases/text_hover_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.315111121212121",
-        "name": "smoothness.tough_scrolling_cases/text_hover_90000_pixels_per_second"
-    },
-    {
-        "duration": "29.886767441860478",
-        "name": "smoothness.tough_texture_upload_cases/background_color_animation"
-    },
-    {
-        "duration": "28.699414171717184",
-        "name": "smoothness.tough_texture_upload_cases/background_color_animation.html"
-    },
-    {
-        "duration": "19.755744197674424",
-        "name": "smoothness.tough_texture_upload_cases/background_color_animation_with_gradient"
-    },
-    {
-        "duration": "19.950798010101018",
-        "name": "smoothness.tough_texture_upload_cases/background_color_animation_with_gradient.html"
-    },
-    {
-        "duration": "19.849395325581398",
-        "name": "smoothness.tough_texture_upload_cases/extra_large_texture_uploads"
-    },
-    {
-        "duration": "20.30039388888889",
-        "name": "smoothness.tough_texture_upload_cases/extra_large_texture_uploads.html"
-    },
-    {
-        "duration": "19.17227911627907",
-        "name": "smoothness.tough_texture_upload_cases/large_texture_uploads"
-    },
-    {
-        "duration": "19.28512119191919",
-        "name": "smoothness.tough_texture_upload_cases/large_texture_uploads.html"
-    },
-    {
-        "duration": "18.354534930232557",
-        "name": "smoothness.tough_texture_upload_cases/medium_texture_uploads"
-    },
-    {
-        "duration": "18.428697020202023",
-        "name": "smoothness.tough_texture_upload_cases/medium_texture_uploads.html"
-    },
-    {
-        "duration": "18.1792325",
-        "name": "smoothness.tough_texture_upload_cases/small_texture_uploads"
-    },
-    {
-        "duration": "19.252555535353537",
-        "name": "smoothness.tough_texture_upload_cases/small_texture_uploads.html"
-    },
-    {
-        "duration": "30.229717141414145",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CICAgICQ15a9NxDIARjIASgBMghBC1XuTk8ezw.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.40264642424243",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CICAgIDQ2Pb-MxCsAhj6ASgBMgi5DLoSO0gPbQ.swf.webglbeta.html"
-    },
-    {
-        "duration": "19.99770706060605",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CICAgKCN39CopQEQoAEY2AQoATIID59gK5hjjIg.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.02665654545454",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CICAgKCNj4HgyAEQeBjYBCgBMgjQpPkOjyWNdw.1.swf.webglbeta.html"
-    },
-    {
-        "duration": "19.954383838383837",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CICAgMDOrcnRGRB4GNgEKAEyCP_ZBSfwUFsj.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.538060606060597",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/CNP2xe_LmqPEKBCsAhj6ASgBMggnyMqth81h8Q.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.12783833333334",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/clip-paths-CICAgMDO7Ye9-gEQ2AUYWigBMgjZxDii6aoK9w.swf.webglbeta.html"
-    },
-    {
-        "duration": "19.999000030303034",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/clip-paths-CILZhLqO_-27bxB4GNgEKAEyCC46kMLBXnMT.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.088707121212124",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/filters-CNLa0t2T47qJ_wEQoAEY2AQoATIIFaIdc7VMBr4.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.021525252525247",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/shapes-CICAgMDO7cfIzwEQ1AMYPCgBMghqY8tqyRCArQ.swf.webglbeta.html"
-    },
-    {
-        "duration": "20.14841417171717",
-        "name": "smoothness.tough_webgl_ad_cases/http://localhost:8000/shapes-CK7ptO3F8bi2KxDQAhiYAigBMgij6QBQtD2gyA.swf.webglbeta.html"
-    },
-    {
-        "duration": "16.541040434343433",
-        "name": "smoothness.tough_webgl_cases/animometer_webgl"
-    },
-    {
-        "duration": "18.563606060606055",
-        "name": "smoothness.tough_webgl_cases/aquarium"
-    },
-    {
-        "duration": "21.121060595959595",
-        "name": "smoothness.tough_webgl_cases/aquarium_20k"
-    },
-    {
-        "duration": "15.86016162121212",
-        "name": "smoothness.tough_webgl_cases/blob"
-    },
-    {
-        "duration": "16.49357573737374",
-        "name": "smoothness.tough_webgl_cases/dynamic_cube_map"
-    },
-    {
-        "duration": "15.625080803030297",
-        "name": "smoothness.tough_webgl_cases/earth"
-    },
-    {
-        "duration": "16.60389903030303",
-        "name": "smoothness.tough_webgl_cases/http://kenrussell.github.io/webgl-animometer/Animometer/tests/3d/webgl.html"
-    },
-    {
-        "duration": "18.649969696969695",
-        "name": "smoothness.tough_webgl_cases/http://webglsamples.org/aquarium/aquarium.html"
-    },
-    {
-        "duration": "15.994959540404041",
-        "name": "smoothness.tough_webgl_cases/http://webglsamples.org/blob/blob.html"
-    },
-    {
-        "duration": "16.567424242424238",
-        "name": "smoothness.tough_webgl_cases/http://webglsamples.org/dynamic-cubemap/dynamic-cubemap.html"
-    },
-    {
-        "duration": "28.61602022222223",
-        "name": "smoothness.tough_webgl_cases/http://www.khronos.org/registry/webgl/sdk/demos/google/nvidia-vertex-buffer-object/index.html"
-    },
-    {
-        "duration": "15.775545419191914",
-        "name": "smoothness.tough_webgl_cases/http://www.khronos.org/registry/webgl/sdk/demos/google/particles/index.html"
-    },
-    {
-        "duration": "15.79988885858585",
-        "name": "smoothness.tough_webgl_cases/http://www.khronos.org/registry/webgl/sdk/demos/google/san-angeles/index.html"
-    },
-    {
-        "duration": "15.770232247474745",
-        "name": "smoothness.tough_webgl_cases/http://www.khronos.org/registry/webgl/sdk/demos/webkit/Earth.html"
-    },
-    {
-        "duration": "15.938393969696973",
-        "name": "smoothness.tough_webgl_cases/http://www.khronos.org/registry/webgl/sdk/demos/webkit/ManyPlanetsDeep.html"
-    },
-    {
-        "duration": "16.562124999999998",
-        "name": "smoothness.tough_webgl_cases/ken_russell"
-    },
-    {
-        "duration": "15.782767686868688",
-        "name": "smoothness.tough_webgl_cases/many_planets_deep"
-    },
-    {
-        "duration": "28.8214140909091",
-        "name": "smoothness.tough_webgl_cases/nvidia_vertex_buffer_object"
-    },
-    {
-        "duration": "15.608212101010103",
-        "name": "smoothness.tough_webgl_cases/particles"
-    },
-    {
-        "duration": "15.810010050505046",
-        "name": "smoothness.tough_webgl_cases/san_angeles"
-    },
-    {
-        "duration": "15.779000000000002",
-        "name": "smoothness.tough_webgl_cases/sans_angeles"
-    },
-    {
-        "duration": "47.1619898989899",
+        "duration": "36.0",
         "name": "speedometer-future/http://browserbench.org/Speedometer/"
     },
     {
-        "duration": "40.33910105050508",
+        "duration": "32.0",
         "name": "speedometer/http://browserbench.org/Speedometer/"
     },
     {
-        "duration": "74.26140400000001",
+        "duration": "64.0",
         "name": "speedometer2-future/Speedometer2"
     },
     {
-        "duration": "76.93698989898992",
+        "duration": "61.0",
         "name": "speedometer2/Speedometer2"
     },
     {
-        "duration": "0.0010000069666666665",
+        "duration": "76.0",
         "name": "system_health.common_desktop/browse:media:flickr_infinite_scroll"
     },
     {
-        "duration": "97.96902020202019",
+        "duration": "104.0",
         "name": "system_health.common_desktop/browse:media:imgur"
     },
     {
-        "duration": "70.31925256565656",
+        "duration": "69.0",
         "name": "system_health.common_desktop/browse:media:pinterest"
     },
     {
-        "duration": "0.0010001659",
+        "duration": "114.0",
         "name": "system_health.common_desktop/browse:media:tumblr"
     },
     {
-        "duration": "76.16398993939394",
+        "duration": "91.0",
         "name": "system_health.common_desktop/browse:media:youtube"
     },
     {
-        "duration": "85.68606060606061",
+        "duration": "87.0",
         "name": "system_health.common_desktop/browse:news:cnn"
     },
     {
-        "duration": "59.89001010101009",
+        "duration": "66.0",
         "name": "system_health.common_desktop/browse:news:flipboard"
     },
     {
-        "duration": "9.999275E-4",
+        "duration": "57.0",
         "name": "system_health.common_desktop/browse:news:hackernews"
     },
     {
-        "duration": "97.49339393939397",
+        "duration": "106.0",
         "name": "system_health.common_desktop/browse:news:nytimes"
     },
     {
-        "duration": "73.19825248484852",
+        "duration": "73.0",
         "name": "system_health.common_desktop/browse:news:reddit"
     },
     {
-        "duration": "9.999275E-4",
+        "duration": "54.0",
         "name": "system_health.common_desktop/browse:search:google"
     },
     {
-        "duration": "39.52054541414144",
+        "duration": "40.0",
         "name": "system_health.common_desktop/browse:search:google_india"
     },
     {
-        "duration": "73.92602016161615",
+        "duration": "84.0",
         "name": "system_health.common_desktop/browse:social:facebook_infinite_scroll"
     },
     {
-        "duration": "84.5228484444444",
+        "duration": "88.0",
         "name": "system_health.common_desktop/browse:social:tumblr_infinite_scroll"
     },
     {
-        "duration": "51.05947468686869",
+        "duration": "51.0",
         "name": "system_health.common_desktop/browse:social:twitter"
     },
     {
-        "duration": "92.67472727272722",
-        "name": "system_health.common_desktop/browse:social:twitter_infinite_scroll"
-    },
-    {
-        "duration": "76.19918181818181",
+        "duration": "81.0",
         "name": "system_health.common_desktop/browse:tech:discourse_infinite_scroll"
     },
     {
-        "duration": "72.87380812121211",
+        "duration": "75.0",
         "name": "system_health.common_desktop/browse:tools:earth"
     },
     {
-        "duration": "60.475020181818174",
+        "duration": "62.0",
         "name": "system_health.common_desktop/browse:tools:maps"
     },
     {
-        "duration": "24.86998991919193",
+        "duration": "25.0",
         "name": "system_health.common_desktop/browse_accessibility:tech:codesearch"
     },
     {
-        "duration": "9.999871E-4",
-        "name": "system_health.common_desktop/browse_accessibility:tools:gmail_compose"
-    },
-    {
-        "duration": "17.385585858585856",
+        "duration": "18.0",
         "name": "system_health.common_desktop/load:chrome:blank"
     },
     {
-        "duration": "21.503313111111105",
+        "duration": "22.0",
         "name": "system_health.common_desktop/load:games:alphabetty"
     },
     {
-        "duration": "23.74739394949495",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load:games:bubbles"
     },
     {
-        "duration": "20.517969707070705",
+        "duration": "21.0",
         "name": "system_health.common_desktop/load:games:lazors"
     },
     {
-        "duration": "25.57121216161616",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:games:miniclip"
     },
     {
-        "duration": "28.07942426262626",
+        "duration": "29.0",
         "name": "system_health.common_desktop/load:games:spychase"
     },
     {
-        "duration": "36.58223230303031",
+        "duration": "38.0",
         "name": "system_health.common_desktop/load:media:9gag"
     },
     {
-        "duration": "24.818383868686865",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load:media:dailymotion"
     },
     {
-        "duration": "22.30925253535352",
+        "duration": "22.0",
         "name": "system_health.common_desktop/load:media:google_images"
     },
     {
-        "duration": "26.987484828282835",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:media:imgur"
     },
     {
-        "duration": "28.178050515151515",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:media:soundcloud"
     },
     {
-        "duration": "25.553939373737386",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:media:youtube"
     },
     {
-        "duration": "23.236858545454556",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load:news:bbc"
     },
     {
-        "duration": "28.328363606060613",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:news:cnn"
     },
     {
-        "duration": "22.742545464646454",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:news:flipboard"
     },
     {
-        "duration": "20.078616202020207",
+        "duration": "21.0",
         "name": "system_health.common_desktop/load:news:hackernews"
     },
     {
-        "duration": "26.382060595959594",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:news:nytimes"
     },
     {
-        "duration": "29.068868676767686",
+        "duration": "29.0",
         "name": "system_health.common_desktop/load:news:qq"
     },
     {
-        "duration": "22.08726263636364",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:news:reddit"
     },
     {
-        "duration": "22.229707101010117",
+        "duration": "34.0",
         "name": "system_health.common_desktop/load:news:wikipedia"
     },
     {
-        "duration": "22.9858282929293",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:search:amazon"
     },
     {
-        "duration": "21.70505047474748",
+        "duration": "22.0",
         "name": "system_health.common_desktop/load:search:baidu"
     },
     {
-        "duration": "23.59198991919192",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load:search:ebay"
     },
     {
-        "duration": "21.68789897979799",
+        "duration": "22.0",
         "name": "system_health.common_desktop/load:search:google"
     },
     {
-        "duration": "23.68709085858585",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:search:taobao"
     },
     {
-        "duration": "21.300454545454535",
+        "duration": "21.0",
         "name": "system_health.common_desktop/load:search:yahoo"
     },
     {
-        "duration": "21.575919202020202",
+        "duration": "22.0",
         "name": "system_health.common_desktop/load:search:yandex"
     },
     {
-        "duration": "23.479161626262627",
+        "duration": "31.0",
         "name": "system_health.common_desktop/load:social:instagram"
     },
     {
-        "duration": "23.819525292929296",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:social:pinterest"
     },
     {
-        "duration": "23.02353537373738",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:social:vk"
     },
     {
-        "duration": "36.22334343434344",
+        "duration": "37.0",
         "name": "system_health.common_desktop/load:tools:docs"
     },
     {
-        "duration": "34.85987873737375",
+        "duration": "33.0",
         "name": "system_health.common_desktop/load:tools:drive"
     },
     {
-        "duration": "23.937070686868697",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:tools:dropbox"
     },
     {
-        "duration": "28.185252515151504",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:tools:gmail"
     },
     {
-        "duration": "22.791636343434334",
+        "duration": "23.0",
         "name": "system_health.common_desktop/load:tools:stackoverflow"
     },
     {
-        "duration": "28.935212131313133",
+        "duration": "31.0",
         "name": "system_health.common_desktop/load:tools:weather"
     },
     {
-        "duration": "22.45317169696969",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load_accessibility:media:wikipedia"
     },
     {
-        "duration": "30.412717171717173",
+        "duration": "24.0",
         "name": "system_health.common_desktop/load_accessibility:shopping:amazon"
     },
     {
-        "duration": "133.43395949494948",
+        "duration": "131.0",
         "name": "system_health.common_desktop/long_running:tools:gmail-background"
     },
     {
-        "duration": "344.60642424242434",
+        "duration": "135.0",
         "name": "system_health.common_desktop/long_running:tools:gmail-foreground"
     },
     {
-        "duration": "147.41508084848485",
+        "duration": "215.0",
         "name": "system_health.common_desktop/multitab:misc:typical24"
     },
     {
-        "duration": "9.999275E-4",
+        "duration": "55.0",
         "name": "system_health.common_desktop/play:media:google_play_music"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "system_health.common_desktop/play:media:pandora"
-    },
-    {
-        "duration": "9.999672333333334E-4",
+        "duration": "56.0",
         "name": "system_health.common_desktop/play:media:soundcloud"
     },
     {
-        "duration": "0.0013333955999999998",
-        "name": "system_health.memory_desktop/browse:media:flickr_infinite_scroll"
-    },
-    {
-        "duration": "207.39890913131316",
+        "duration": "70.0",
         "name": "system_health.memory_desktop/browse:media:imgur"
     },
     {
-        "duration": "187.18185864646463",
+        "duration": "61.0",
         "name": "system_health.memory_desktop/browse:media:pinterest"
     },
     {
-        "duration": "177.29151511111118",
-        "name": "system_health.memory_desktop/browse:media:tumblr"
-    },
-    {
-        "duration": "181.09774749494943",
+        "duration": "61.0",
         "name": "system_health.memory_desktop/browse:media:youtube"
     },
     {
-        "duration": "177.24176769696976",
+        "duration": "58.0",
         "name": "system_health.memory_desktop/browse:news:cnn"
     },
     {
-        "duration": "148.48966658585857",
+        "duration": "51.0",
         "name": "system_health.memory_desktop/browse:news:flipboard"
     },
     {
-        "duration": "202.7948484848485",
+        "duration": "71.0",
         "name": "system_health.memory_desktop/browse:news:nytimes"
     },
     {
-        "duration": "182.0874342828282",
+        "duration": "61.0",
         "name": "system_health.memory_desktop/browse:news:reddit"
     },
     {
-        "duration": "0.0010001659",
+        "duration": "48.0",
         "name": "system_health.memory_desktop/browse:search:google"
     },
     {
-        "duration": "106.84377775757571",
+        "duration": "36.0",
         "name": "system_health.memory_desktop/browse:search:google_india"
     },
     {
-        "duration": "189.3297878989899",
+        "duration": "64.0",
         "name": "system_health.memory_desktop/browse:social:facebook_infinite_scroll"
     },
     {
-        "duration": "192.46958583838384",
+        "duration": "65.0",
         "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll"
     },
     {
-        "duration": "138.19091905050504",
+        "duration": "46.0",
         "name": "system_health.memory_desktop/browse:social:twitter"
     },
     {
-        "duration": "185.25912117171723",
+        "duration": "63.0",
         "name": "system_health.memory_desktop/browse:tech:discourse_infinite_scroll"
     },
     {
-        "duration": "160.87625256565656",
+        "duration": "55.0",
         "name": "system_health.memory_desktop/browse:tools:earth"
     },
     {
-        "duration": "151.4894545050505",
+        "duration": "52.0",
         "name": "system_health.memory_desktop/browse:tools:maps"
     },
     {
-        "duration": "61.42696967676766",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/browse_accessibility:tech:codesearch"
     },
     {
-        "duration": "45.698888939393946",
+        "duration": "16.0",
         "name": "system_health.memory_desktop/load:chrome:blank"
     },
     {
-        "duration": "57.96254540404042",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:games:alphabetty"
     },
     {
-        "duration": "58.257434343434355",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:games:bubbles"
     },
     {
-        "duration": "55.09436368686868",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:games:lazors"
     },
     {
-        "duration": "63.40618178787878",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:games:miniclip"
     },
     {
-        "duration": "71.10260595959596",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:games:spychase"
     },
     {
-        "duration": "84.00951517171718",
+        "duration": "28.0",
         "name": "system_health.memory_desktop/load:media:9gag"
     },
     {
-        "duration": "60.009393949494964",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:media:dailymotion"
     },
     {
-        "duration": "59.327474686868676",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:media:google_images"
     },
     {
-        "duration": "67.76846467676766",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:media:imgur"
     },
     {
-        "duration": "66.54091918181817",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:media:soundcloud"
     },
     {
-        "duration": "60.26443433333334",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:media:youtube"
     },
     {
-        "duration": "60.99940404040403",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:news:bbc"
     },
     {
-        "duration": "69.40436362626264",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:news:cnn"
     },
     {
-        "duration": "58.610505070707056",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:news:flipboard"
     },
     {
-        "duration": "55.72650505050506",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:news:hackernews"
     },
     {
-        "duration": "64.24272723232322",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:news:nytimes"
     },
     {
-        "duration": "72.04975757575758",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:news:qq"
     },
     {
-        "duration": "57.99711107070705",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:news:reddit"
     },
     {
-        "duration": "58.940464545454546",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:news:wikipedia"
     },
     {
-        "duration": "58.136141434343436",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:search:amazon"
     },
     {
-        "duration": "56.168050494949505",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:search:baidu"
     },
     {
-        "duration": "60.537070666666665",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:search:ebay"
     },
     {
-        "duration": "57.24329293939396",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:search:google"
     },
     {
-        "duration": "59.78401011111112",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:search:taobao"
     },
     {
-        "duration": "56.21350507070709",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:search:yahoo"
     },
     {
-        "duration": "56.70408086868685",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:search:yandex"
     },
     {
-        "duration": "60.89545452525254",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:social:instagram"
     },
     {
-        "duration": "62.79710105050507",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:social:pinterest"
     },
     {
-        "duration": "59.54065657575757",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:social:vk"
     },
     {
-        "duration": "64.36946467676769",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:tools:docs"
     },
     {
-        "duration": "74.16734335353536",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:tools:drive"
     },
     {
-        "duration": "60.080949515151495",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:tools:dropbox"
     },
     {
-        "duration": "68.31734332323238",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:tools:gmail"
     },
     {
-        "duration": "60.53708079797982",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:tools:stackoverflow"
     },
     {
-        "duration": "70.34837381818183",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:tools:weather"
     },
     {
-        "duration": "57.45111111111114",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load_accessibility:media:wikipedia"
     },
     {
-        "duration": "64.16678783838383",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load_accessibility:shopping:amazon"
     },
     {
-        "duration": "428.346282828283",
+        "duration": "143.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-background"
     },
     {
-        "duration": "428.1560403030304",
+        "duration": "141.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-foreground"
     },
     {
-        "duration": "315.44431313131315",
+        "duration": "121.0",
         "name": "system_health.memory_desktop/multitab:misc:typical24"
     },
     {
-        "duration": "0.0012000083599999999",
-        "name": "system_health.memory_desktop/play:media:google_play_music"
-    },
-    {
-        "duration": "0.0013333955999999998",
-        "name": "system_health.memory_desktop/play:media:pandora"
-    },
-    {
-        "duration": "9.999275E-4",
-        "name": "system_health.memory_desktop/play:media:soundcloud"
-    },
-    {
-        "duration": "108.51674743434346",
+        "duration": "113.0",
         "name": "tab_switching.typical_25/multitab:misc:typical24"
     },
     {
-        "duration": "28.172494989898983",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/beqojupo/1/quiet?JS_FULL_SCREEN_INVALIDATION"
-    },
-    {
-        "duration": "25.57725252525252",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/covoqi/1/quiet?NEW_TILINGS"
-    },
-    {
-        "duration": "22.48349491919191",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/falefice/1/quiet?CC_POSTER_CIRCLE"
-    },
-    {
-        "duration": "23.398585858585854",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/giqafofe/1/quiet?JS_POSTER_CIRCLE"
-    },
-    {
-        "duration": "20.92841416161616",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/jevibahi/4/quiet?JS_SCROLL_200_LAYER_GRID"
-    },
-    {
-        "duration": "25.13015147474748",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/pixavefe/1/quiet?CC_SCROLL_TEXT_ONLY"
-    },
-    {
-        "duration": "21.05167675757576",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/wixadinu/2/quiet?JS_SCROLL_TEXT_ONLY"
-    },
-    {
-        "duration": "21.248201999999996",
-        "name": "thread_times.tough_compositor_cases/http://jsbin.com/yakagevo/1/quiet?CC_SCROLL_200_LAYER_GRID"
-    },
-    {
-        "duration": "16.63638385858586",
-        "name": "thread_times.tough_scrolling_cases/canvas_05000_pixels_per_second"
-    },
-    {
-        "duration": "16.0447171969697",
-        "name": "thread_times.tough_scrolling_cases/canvas_10000_pixels_per_second"
-    },
-    {
-        "duration": "13.038454540404034",
-        "name": "thread_times.tough_scrolling_cases/canvas_15000_pixels_per_second"
-    },
-    {
-        "duration": "12.044838328282829",
-        "name": "thread_times.tough_scrolling_cases/canvas_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.640030348484846",
-        "name": "thread_times.tough_scrolling_cases/canvas_30000_pixels_per_second"
-    },
-    {
-        "duration": "10.076363641414142",
-        "name": "thread_times.tough_scrolling_cases/canvas_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.683828292929297",
-        "name": "thread_times.tough_scrolling_cases/canvas_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.447575792929293",
-        "name": "thread_times.tough_scrolling_cases/canvas_60000_pixels_per_second"
-    },
-    {
-        "duration": "9.145929297979794",
-        "name": "thread_times.tough_scrolling_cases/canvas_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.961777838383837",
-        "name": "thread_times.tough_scrolling_cases/canvas_90000_pixels_per_second"
-    },
-    {
-        "duration": "34.83318177777777",
-        "name": "thread_times.tough_scrolling_cases/text_05000_pixels_per_second"
-    },
-    {
-        "duration": "15.313626257575756",
-        "name": "thread_times.tough_scrolling_cases/text_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.59582825252525",
-        "name": "thread_times.tough_scrolling_cases/text_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.91569700505051",
-        "name": "thread_times.tough_scrolling_cases/text_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.25633334848485",
-        "name": "thread_times.tough_scrolling_cases/text_30000_pixels_per_second"
-    },
-    {
-        "duration": "10.671505040404043",
-        "name": "thread_times.tough_scrolling_cases/text_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.344333449494947",
-        "name": "thread_times.tough_scrolling_cases/text_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.039353525252526",
-        "name": "thread_times.tough_scrolling_cases/text_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.806727313131312",
-        "name": "thread_times.tough_scrolling_cases/text_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.637646499999995",
-        "name": "thread_times.tough_scrolling_cases/text_90000_pixels_per_second"
-    },
-    {
-        "duration": "17.830313131313126",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_05000_pixels_per_second"
-    },
-    {
-        "duration": "16.559272767676767",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_10000_pixels_per_second"
-    },
-    {
-        "duration": "13.911222272727269",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_15000_pixels_per_second"
-    },
-    {
-        "duration": "12.56742427777778",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_20000_pixels_per_second"
-    },
-    {
-        "duration": "11.141333323232319",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_30000_pixels_per_second"
-    },
-    {
-        "duration": "10.640161611111107",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_40000_pixels_per_second"
-    },
-    {
-        "duration": "10.13763637878788",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_50000_pixels_per_second"
-    },
-    {
-        "duration": "9.867434358585857",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_60000_pixels_per_second"
-    },
-    {
-        "duration": "9.55034346464646",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_75000_pixels_per_second"
-    },
-    {
-        "duration": "9.458282833333334",
-        "name": "thread_times.tough_scrolling_cases/text_constant_full_page_raster_90000_pixels_per_second"
-    },
-    {
-        "duration": "15.934656560606062",
-        "name": "thread_times.tough_scrolling_cases/text_hover_05000_pixels_per_second"
-    },
-    {
-        "duration": "14.77061612626263",
-        "name": "thread_times.tough_scrolling_cases/text_hover_10000_pixels_per_second"
-    },
-    {
-        "duration": "12.5120403989899",
-        "name": "thread_times.tough_scrolling_cases/text_hover_15000_pixels_per_second"
-    },
-    {
-        "duration": "11.235535338383837",
-        "name": "thread_times.tough_scrolling_cases/text_hover_20000_pixels_per_second"
-    },
-    {
-        "duration": "10.06039392424242",
-        "name": "thread_times.tough_scrolling_cases/text_hover_30000_pixels_per_second"
-    },
-    {
-        "duration": "9.483515136363637",
-        "name": "thread_times.tough_scrolling_cases/text_hover_40000_pixels_per_second"
-    },
-    {
-        "duration": "9.163828257575753",
-        "name": "thread_times.tough_scrolling_cases/text_hover_50000_pixels_per_second"
-    },
-    {
-        "duration": "8.836565681818183",
-        "name": "thread_times.tough_scrolling_cases/text_hover_60000_pixels_per_second"
-    },
-    {
-        "duration": "8.574262636363637",
-        "name": "thread_times.tough_scrolling_cases/text_hover_75000_pixels_per_second"
-    },
-    {
-        "duration": "8.537939429292932",
-        "name": "thread_times.tough_scrolling_cases/text_hover_90000_pixels_per_second"
-    },
-    {
-        "duration": "10.713727277777776",
+        "duration": "11.0",
         "name": "tracing.tracing_with_background_memory_infra/Facebook"
     },
     {
-        "duration": "11.191767717171716",
+        "duration": "11.0",
         "name": "tracing.tracing_with_background_memory_infra/Wikipedia"
     },
     {
-        "duration": "9.35317175757576",
+        "duration": "10.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.amazon.com"
     },
     {
-        "duration": "10.2252221969697",
+        "duration": "11.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.ask.com/"
     },
     {
-        "duration": "9.806010101010106",
+        "duration": "10.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.bing.com/"
     },
     {
-        "duration": "9.9939495",
+        "duration": "10.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.yahoo.com/"
     },
     {
-        "duration": "11.74751515656566",
+        "duration": "12.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.youtube.com"
     },
     {
-        "duration": "22.485686853535345",
+        "duration": "11.0",
         "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/#hl=en&q=barack+obama"
     },
     {
-        "duration": "13.11601014646465",
+        "duration": "14.0",
         "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/calendar/"
     },
     {
-        "duration": "0.0010001659",
-        "name": "v8.browsing_desktop-future/browse:media:flickr_infinite_scroll"
-    },
-    {
-        "duration": "231.88872727272724",
+        "duration": "249.0",
         "name": "v8.browsing_desktop-future/browse:media:imgur"
     },
     {
-        "duration": "80.89534339393943",
+        "duration": "77.0",
         "name": "v8.browsing_desktop-future/browse:media:pinterest"
     },
     {
-        "duration": "84.93430303030304",
+        "duration": "140.0",
         "name": "v8.browsing_desktop-future/browse:media:tumblr"
     },
     {
-        "duration": "96.28224242424241",
+        "duration": "96.0",
         "name": "v8.browsing_desktop-future/browse:media:youtube"
     },
     {
-        "duration": "135.44675743434345",
+        "duration": "122.0",
         "name": "v8.browsing_desktop-future/browse:news:cnn"
     },
     {
-        "duration": "0.00100002286",
-        "name": "v8.browsing_desktop-future/browse:news:flipboard"
-    },
-    {
-        "duration": "9.999871E-4",
-        "name": "v8.browsing_desktop-future/browse:news:hackernews"
-    },
-    {
-        "duration": "139.11240404040404",
-        "name": "v8.browsing_desktop-future/browse:news:nytimes"
-    },
-    {
-        "duration": "87.88215151515152",
-        "name": "v8.browsing_desktop-future/browse:news:reddit"
-    },
-    {
-        "duration": "58.09329290909093",
+        "duration": "60.0",
         "name": "v8.browsing_desktop-future/browse:search:google"
     },
     {
-        "duration": "42.20118181818184",
+        "duration": "43.0",
         "name": "v8.browsing_desktop-future/browse:search:google_india"
     },
     {
-        "duration": "98.05891923232323",
+        "duration": "99.0",
         "name": "v8.browsing_desktop-future/browse:social:facebook_infinite_scroll"
     },
     {
-        "duration": "105.47064646464645",
+        "duration": "107.0",
         "name": "v8.browsing_desktop-future/browse:social:tumblr_infinite_scroll"
     },
     {
-        "duration": "57.849323232323265",
+        "duration": "56.0",
         "name": "v8.browsing_desktop-future/browse:social:twitter"
     },
     {
-        "duration": "119.28043444444444",
-        "name": "v8.browsing_desktop-future/browse:social:twitter_infinite_scroll"
-    },
-    {
-        "duration": "110.93080808080808",
+        "duration": "113.0",
         "name": "v8.browsing_desktop-future/browse:tech:discourse_infinite_scroll"
     },
     {
-        "duration": "105.05406064646465",
+        "duration": "104.0",
         "name": "v8.browsing_desktop-future/browse:tools:earth"
     },
     {
-        "duration": "80.53191915151517",
+        "duration": "81.0",
         "name": "v8.browsing_desktop-future/browse:tools:maps"
     },
     {
-        "duration": "0.0010000467",
-        "name": "v8.browsing_desktop/browse:media:flickr_infinite_scroll"
-    },
-    {
-        "duration": "250.189606060606",
+        "duration": "247.0",
         "name": "v8.browsing_desktop/browse:media:imgur"
     },
     {
-        "duration": "81.52414141414143",
+        "duration": "77.0",
         "name": "v8.browsing_desktop/browse:media:pinterest"
     },
     {
-        "duration": "84.41895963636362",
+        "duration": "141.0",
         "name": "v8.browsing_desktop/browse:media:tumblr"
     },
     {
-        "duration": "96.44750501010101",
+        "duration": "96.0",
         "name": "v8.browsing_desktop/browse:media:youtube"
     },
     {
-        "duration": "132.24963612121212",
+        "duration": "121.0",
         "name": "v8.browsing_desktop/browse:news:cnn"
     },
     {
-        "duration": "9.999275E-4",
-        "name": "v8.browsing_desktop/browse:news:flipboard"
-    },
-    {
-        "duration": "9.999871E-4",
-        "name": "v8.browsing_desktop/browse:news:hackernews"
-    },
-    {
-        "duration": "138.06498989898992",
+        "duration": "146.0",
         "name": "v8.browsing_desktop/browse:news:nytimes"
     },
     {
-        "duration": "88.60219195959591",
+        "duration": "79.0",
         "name": "v8.browsing_desktop/browse:news:reddit"
     },
     {
-        "duration": "58.15426258585859",
+        "duration": "58.0",
         "name": "v8.browsing_desktop/browse:search:google"
     },
     {
-        "duration": "42.216141393939395",
+        "duration": "43.0",
         "name": "v8.browsing_desktop/browse:search:google_india"
     },
     {
-        "duration": "97.3823837979798",
+        "duration": "97.0",
         "name": "v8.browsing_desktop/browse:social:facebook_infinite_scroll"
     },
     {
-        "duration": "104.57660606060608",
+        "duration": "107.0",
         "name": "v8.browsing_desktop/browse:social:tumblr_infinite_scroll"
     },
     {
-        "duration": "56.72188892929295",
+        "duration": "57.0",
         "name": "v8.browsing_desktop/browse:social:twitter"
     },
     {
-        "duration": "115.95925252525245",
-        "name": "v8.browsing_desktop/browse:social:twitter_infinite_scroll"
-    },
-    {
-        "duration": "110.61260606060605",
+        "duration": "113.0",
         "name": "v8.browsing_desktop/browse:tech:discourse_infinite_scroll"
     },
     {
-        "duration": "106.01424250505049",
+        "duration": "105.0",
         "name": "v8.browsing_desktop/browse:tools:earth"
     },
     {
-        "duration": "80.0400404040404",
+        "duration": "81.0",
         "name": "v8.browsing_desktop/browse:tools:maps"
     },
     {
-        "duration": "0.00150001045",
-        "name": "wasm/AsmJsZenGarden"
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/AdsAMPAds_cold"
     },
     {
-        "duration": "47.291363641414144",
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/AdsAMPAds_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/AdsAMPAds_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_cold"
+    },
+    {
+        "duration": "37.0",
+        "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_warm"
+    },
+    {
+        "duration": "44.0",
+        "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_cold"
+    },
+    {
+        "duration": "71.0",
+        "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_hot"
+    },
+    {
+        "duration": "57.0",
+        "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_warm"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://edition.cnn.com_cold"
+    },
+    {
+        "duration": "45.0",
+        "name": "v8.runtime_stats.top_25/http://edition.cnn.com_hot"
+    },
+    {
+        "duration": "41.0",
+        "name": "v8.runtime_stats.top_25/http://edition.cnn.com_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://inbox.google.com_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://inbox.google.com_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://inbox.google.com_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_cold"
+    },
+    {
+        "duration": "40.0",
+        "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_hot"
+    },
+    {
+        "duration": "37.0",
+        "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_warm"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://meta.discourse.org_cold"
+    },
+    {
+        "duration": "39.0",
+        "name": "v8.runtime_stats.top_25/http://meta.discourse.org_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://meta.discourse.org_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_hot"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_cold"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_hot"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_hot"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_hot"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_warm"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_cold"
+    },
+    {
+        "duration": "39.0",
+        "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_warm"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://weibo.com_cold"
+    },
+    {
+        "duration": "40.0",
+        "name": "v8.runtime_stats.top_25/http://weibo.com_hot"
+    },
+    {
+        "duration": "37.0",
+        "name": "v8.runtime_stats.top_25/http://weibo.com_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://world.taobao.com_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://world.taobao.com_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://world.taobao.com_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_hot"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_warm"
+    },
+    {
+        "duration": "31.0",
+        "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_cold"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_warm"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_cold"
+    },
+    {
+        "duration": "41.0",
+        "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_hot"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_warm"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_warm"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_cold"
+    },
+    {
+        "duration": "42.0",
+        "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_hot"
+    },
+    {
+        "duration": "39.0",
+        "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_warm"
+    },
+    {
+        "duration": "67.0",
+        "name": "v8.runtime_stats.top_25/http://www.qq.com_cold"
+    },
+    {
+        "duration": "76.0",
+        "name": "v8.runtime_stats.top_25/http://www.qq.com_hot"
+    },
+    {
+        "duration": "69.0",
+        "name": "v8.runtime_stats.top_25/http://www.qq.com_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.reddit.com_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://www.reddit.com_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://www.reddit.com_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_cold"
+    },
+    {
+        "duration": "39.0",
+        "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_cold"
+    },
+    {
+        "duration": "37.0",
+        "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_warm"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_cold"
+    },
+    {
+        "duration": "37.0",
+        "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_warm"
+    },
+    {
+        "duration": "46.0",
+        "name": "v8.runtime_stats.top_25/https://adwords.google.com_cold"
+    },
+    {
+        "duration": "59.0",
+        "name": "v8.runtime_stats.top_25/https://adwords.google.com_hot"
+    },
+    {
+        "duration": "57.0",
+        "name": "v8.runtime_stats.top_25/https://adwords.google.com_warm"
+    },
+    {
+        "duration": "30.0",
+        "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_cold"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_hot"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_warm"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_cold"
+    },
+    {
+        "duration": "41.0",
+        "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_hot"
+    },
+    {
+        "duration": "43.0",
+        "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_warm"
+    },
+    {
+        "duration": "32.0",
+        "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_hot"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_warm"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_cold"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_hot"
+    },
+    {
+        "duration": "33.0",
+        "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_warm"
+    },
+    {
+        "duration": "34.0",
+        "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_cold"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_hot"
+    },
+    {
+        "duration": "36.0",
+        "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_warm"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_cold"
+    },
+    {
+        "duration": "43.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_hot"
+    },
+    {
+        "duration": "40.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_warm"
+    },
+    {
+        "duration": "35.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com_cold"
+    },
+    {
+        "duration": "41.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com_hot"
+    },
+    {
+        "duration": "38.0",
+        "name": "v8.runtime_stats.top_25/https://www.youtube.com_warm"
+    },
+    {
+        "duration": "16.0",
         "name": "wasm/WasmSpaceBuggy"
     },
     {
-        "duration": "116.5097373737374",
-        "name": "wasm/WasmStylizedRenderer"
-    },
-    {
-        "duration": "104.80597985858586",
-        "name": "wasm/WasmSunTemple"
-    },
-    {
-        "duration": "58.15015152020203",
+        "duration": "18.0",
         "name": "wasm/WasmTanks"
     },
     {
-        "duration": "114.43171709090916",
+        "duration": "34.0",
         "name": "wasm/WasmZenGarden"
     },
     {
-        "duration": "68.14915151515152",
+        "duration": "35.0",
         "name": "webrtc/10s_datachannel_transfer"
     },
     {
-        "duration": "21.731161616161614",
+        "duration": "22.0",
         "name": "webrtc/canvas_capture_peer_connection"
     },
     {
-        "duration": "31.167606050505032",
+        "duration": "32.0",
         "name": "webrtc/codec_constraints_h264"
     },
     {
-        "duration": "31.151949505050506",
+        "duration": "32.0",
         "name": "webrtc/codec_constraints_vp8"
     },
     {
-        "duration": "31.11636367676769",
+        "duration": "32.0",
         "name": "webrtc/codec_constraints_vp9"
     },
     {
-        "duration": "19.85481824242424",
+        "duration": "20.0",
         "name": "webrtc/hd_local_stream_10s"
     },
     {
-        "duration": "57.42817169696971",
+        "duration": "53.0",
         "name": "webrtc/multiple_peerconnections"
     },
     {
-        "duration": "72.67151521212121",
+        "duration": "57.0",
         "name": "webrtc/pause_play_peerconnections"
     }
 ]
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/win10_shard_map.json b/tools/perf/core/shard_maps/win10_shard_map.json
index 1a4c2f30..3562446 100644
--- a/tools/perf/core/shard_maps/win10_shard_map.json
+++ b/tools/perf/core/shard_maps/win10_shard_map.json
@@ -8,8 +8,29 @@
             "power.desktop": {},
             "speedometer-future": {},
             "blink_perf.owp_storage": {},
-            "memory.desktop": {},
-            "start_with_url.warm.startup_pages": {},
+            "memory.desktop": {
+                "end": 1
+            }
+        }
+    },
+    "1": {
+        "benchmarks": {
+            "memory.desktop": {
+                "begin": 1,
+                "end": 5
+            }
+        }
+    },
+    "2": {
+        "benchmarks": {
+            "memory.desktop": {
+                "begin": 5
+            },
+            "start_with_url.warm.startup_pages": {}
+        }
+    },
+    "3": {
+        "benchmarks": {
             "wasm": {},
             "dummy_benchmark.histogram_benchmark_1": {},
             "speedometer": {},
@@ -18,27 +39,65 @@
             "dummy_benchmark.noisy_benchmark_1": {},
             "blink_perf.svg": {},
             "system_health.webview_startup": {},
-            "speedometer2-future": {},
+            "v8.browsing_mobile": {},
             "jetstream": {},
             "smoothness.tough_pinch_zoom_cases": {},
+            "speedometer2-future": {},
             "power.typical_10_mobile": {},
             "v8.runtime_stats.top_25": {
-                "end": 83
+                "end": 12
             }
         }
     },
-    "1": {
+    "4": {
         "benchmarks": {
             "v8.runtime_stats.top_25": {
-                "begin": 83
+                "begin": 12,
+                "end": 47
+            }
+        }
+    },
+    "5": {
+        "benchmarks": {
+            "v8.runtime_stats.top_25": {
+                "begin": 47,
+                "end": 84
+            }
+        }
+    },
+    "6": {
+        "benchmarks": {
+            "v8.runtime_stats.top_25": {
+                "begin": 84,
+                "end": 124
+            }
+        }
+    },
+    "7": {
+        "benchmarks": {
+            "v8.runtime_stats.top_25": {
+                "begin": 124
             },
             "loading.mobile": {},
             "speedometer2": {},
-            "v8.browsing_desktop-future": {},
+            "v8.browsing_desktop-future": {
+                "end": 15
+            }
+        }
+    },
+    "8": {
+        "benchmarks": {
+            "v8.browsing_desktop-future": {
+                "begin": 15
+            },
             "webrtc": {},
             "blink_perf.shadow_dom": {},
             "blink_perf.events": {},
-            "blink_perf.layout": {},
+            "blink_perf.layout": {}
+        }
+    },
+    "9": {
+        "benchmarks": {
             "memory.long_running_idle_gmail_background_tbmv2": {},
             "tab_switching.typical_25": {},
             "blink_perf.dom": {},
@@ -46,60 +105,166 @@
             "start_with_url.cold.startup_pages": {},
             "blink_perf.bindings": {},
             "system_health.memory_desktop": {
-                "end": 25
+                "end": 6
             }
         }
     },
-    "2": {
+    "10": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 25
+                "begin": 6,
+                "end": 20
+            }
+        }
+    },
+    "11": {
+        "benchmarks": {
+            "system_health.memory_desktop": {
+                "begin": 20,
+                "end": 41
+            }
+        }
+    },
+    "12": {
+        "benchmarks": {
+            "system_health.memory_desktop": {
+                "begin": 41,
+                "end": 53
+            }
+        }
+    },
+    "13": {
+        "benchmarks": {
+            "system_health.memory_desktop": {
+                "begin": 53,
+                "end": 62
+            }
+        }
+    },
+    "14": {
+        "benchmarks": {
+            "system_health.memory_desktop": {
+                "begin": 62
             },
             "media.desktop": {},
             "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
             "rasterize_and_record_micro.partial_invalidation": {},
-            "v8.browsing_desktop": {},
-            "blink_perf.parser": {},
-            "memory.top_10_mobile": {},
-            "blink_perf.canvas": {},
-            "loading.desktop": {
-                "end": 2
+            "v8.browsing_desktop": {
+                "end": 10
             }
         }
     },
-    "3": {
+    "15": {
+        "benchmarks": {
+            "v8.browsing_desktop": {
+                "begin": 10
+            },
+            "blink_perf.parser": {},
+            "memory.top_10_mobile": {},
+            "blink_perf.canvas": {
+                "end": 14
+            }
+        }
+    },
+    "16": {
+        "benchmarks": {
+            "blink_perf.canvas": {
+                "begin": 14
+            },
+            "loading.desktop": {
+                "end": 36
+            }
+        }
+    },
+    "17": {
         "benchmarks": {
             "loading.desktop": {
-                "begin": 2
+                "begin": 36,
+                "end": 67
+            }
+        }
+    },
+    "18": {
+        "benchmarks": {
+            "loading.desktop": {
+                "begin": 67,
+                "end": 96
+            }
+        }
+    },
+    "19": {
+        "benchmarks": {
+            "loading.desktop": {
+                "begin": 96
             },
             "dromaeo": {},
             "kraken": {},
             "oortonline_tbmv2": {},
             "system_health.common_desktop": {
-                "end": 62
+                "end": 16
             }
         }
     },
-    "4": {
+    "20": {
         "benchmarks": {
             "system_health.common_desktop": {
-                "begin": 62
+                "begin": 16,
+                "end": 54
+            }
+        }
+    },
+    "21": {
+        "benchmarks": {
+            "system_health.common_desktop": {
+                "begin": 54
             },
             "rasterize_and_record_micro.top_25": {},
             "dummy_benchmark.stable_benchmark_1": {},
             "system_health.memory_mobile": {},
-            "rendering.desktop": {},
+            "rendering.desktop": {
+                "end": 5
+            }
+        }
+    },
+    "22": {
+        "benchmarks": {
+            "rendering.desktop": {
+                "begin": 5,
+                "end": 61
+            }
+        }
+    },
+    "23": {
+        "benchmarks": {
+            "rendering.desktop": {
+                "begin": 61,
+                "end": 121
+            }
+        }
+    },
+    "24": {
+        "benchmarks": {
+            "rendering.desktop": {
+                "begin": 121,
+                "end": 196
+            }
+        }
+    },
+    "25": {
+        "benchmarks": {
+            "rendering.desktop": {
+                "begin": 196
+            },
             "blink_perf.css": {},
-            "v8.browsing_mobile": {},
             "blink_perf.paint": {},
             "tracing.tracing_with_background_memory_infra": {}
         }
     },
     "extra_infos": {
-        "num_stories": 1832,
-        "predicted_min_shard_time": 13278.596959395232,
-        "predicted_min_shard_index": 4,
-        "predicted_max_shard_time": 13411.964187257567,
+        "num_stories": 1830,
+        "predicted_min_shard_time": 2528.0,
+        "predicted_min_shard_index": 3,
+        "predicted_max_shard_time": 3150.0,
         "predicted_max_shard_index": 1
     }
 }
\ No newline at end of file
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index b22494c..087009f 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -243,6 +243,8 @@
 
 android_library("ui_full_java") {
   java_files = [
+    "java/src/org/chromium/ui/AsyncViewStub.java",
+    "java/src/org/chromium/ui/AsyncViewProvider.java",
     "java/src/org/chromium/ui/DropdownAdapter.java",
     "java/src/org/chromium/ui/DropdownDividerDrawable.java",
     "java/src/org/chromium/ui/DropdownItem.java",
@@ -339,12 +341,21 @@
   ]
 }
 
+android_resources("ui_javatest_resources") {
+  custom_package = "org.chromium.test.ui"
+  resource_dirs = [ "junit/res" ]
+}
+
 junit_binary("ui_junit_tests") {
+  package_name = "org.chromium.test.ui"
   java_files = [
+    "junit/src/org/chromium/ui/AsyncViewStubTest.java",
+    "junit/src/org/chromium/ui/AsyncViewProviderTest.java",
     "junit/src/org/chromium/ui/base/ClipboardTest.java",
     "junit/src/org/chromium/ui/base/SelectFileDialogTest.java",
     "junit/src/org/chromium/ui/drawable/StateListDrawableBuilderTest.java",
     "junit/src/org/chromium/ui/text/SpanApplierTest.java",
+    "junit/src/org/chromium/ui/shadows/ShadowAsyncLayoutInflater.java",
     "junit/src/org/chromium/ui/shadows/ShadowAppCompatResources.java",
     "junit/src/org/chromium/ui/shadows/ShadowAppCompatResourcesTest.java",
     "junit/src/org/chromium/ui/shadows/ShadowAnimatedStateListDrawable.java",
@@ -352,6 +363,7 @@
   ]
   deps = [
     ":ui_java",
+    ":ui_javatest_resources",
     "//base:base_java",
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
diff --git a/ui/android/java/res/values/attrs.xml b/ui/android/java/res/values/attrs.xml
index 06c3b266..61ae7c63 100644
--- a/ui/android/java/res/values/attrs.xml
+++ b/ui/android/java/res/values/attrs.xml
@@ -20,4 +20,10 @@
     <declare-styleable name="TextViewWithLeading">
         <attr name="leading" format="reference|dimension"/>
     </declare-styleable>
+    <declare-styleable name="AsyncViewStub">
+        <!-- Supply an identifier for the layout resource to inflate when the AsyncViewStub
+             becomes visible or when forced to do so. The layout resource must be a
+             valid reference to a layout. -->
+        <attr name="layout" format="reference" />
+    </declare-styleable>
 </resources>
diff --git a/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java b/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java
new file mode 100644
index 0000000..16547543
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/AsyncViewProvider.java
@@ -0,0 +1,131 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui;
+
+import android.support.annotation.Nullable;
+import android.view.View;
+
+import org.chromium.base.Callback;
+import org.chromium.base.ThreadUtils;
+
+/**
+ * A provider that encapsulates a {@link View} that is in the view hierarchy to be inflated by
+ * an {@link AsyncViewStub}.
+ * @param <T> type of the {@link View} that this provider encapsulates.
+ */
+public class AsyncViewProvider<T extends View> implements Callback<View> {
+    private int mResId;
+    // Exactly one of mView and mViewStub is non-null at any point.
+    private T mView;
+    private AsyncViewStub mViewStub;
+    private boolean mDestroyed;
+
+    private AsyncViewProvider(AsyncViewStub viewStub, int resId) {
+        assert viewStub != null;
+        mResId = resId;
+        mViewStub = viewStub;
+    }
+
+    @SuppressWarnings("unchecked")
+    private AsyncViewProvider(View view) {
+        assert view != null;
+        mView = (T) view;
+    }
+
+    /**
+     * Returns a provider for a view in the view hierarchy that is to be inflated by {@param
+     * viewStub}.
+     * @param viewStub the {@link AsyncViewStub} that will inflate the view hierarchy containing the
+     *                 {@link View}.
+     * @param resId The resource id of the view that this provider should provide/encapsulate.
+     * @return an {@link AsyncViewProvider} that encapsulates a view with id {@param resId}.
+     */
+    public static <E extends View> AsyncViewProvider<E> of(AsyncViewStub viewStub, int resId) {
+        ThreadUtils.assertOnUiThread();
+        if (viewStub.getInflatedView() != null) {
+            return new AsyncViewProvider<>(viewStub.getInflatedView().findViewById(resId));
+        }
+        AsyncViewProvider<E> provider = new AsyncViewProvider<>(viewStub, resId);
+        viewStub.addOnInflateListener(provider);
+        return provider;
+    }
+
+    /**
+     * Get a provider for a view with id {@param viewResId} that is (or going to be) in the view
+     * hierarchy inflated by the AsyncViewStub with id {@param viewStubResId}.
+     * @param root the {@link View} to use as the context for finding the View/ViewStub that the
+     *             provider encapsulates.
+     * @param viewStubResId the resource id of the AsyncViewStub that inflates the view hierarchy
+     *                      where the encapsulated View lives.
+     * @param viewResId the resource id of the view that the provider should provide/encapsulate.
+     * @return an {@link AsyncViewProvider} that encapsulates a view with id {@param viewResId}.
+     */
+    public static <E extends View> AsyncViewProvider<E> of(
+            View root, int viewStubResId, int viewResId) {
+        ThreadUtils.assertOnUiThread();
+        View viewStub = root.findViewById(viewStubResId);
+        if (viewStub != null && viewStub instanceof AsyncViewStub) {
+            // view stub not yet inflated
+            return of((AsyncViewStub) viewStub, viewResId);
+        }
+        // view stub already inflated, return pre-loaded provider
+        return new AsyncViewProvider<>(root.findViewById(viewResId));
+    }
+
+    @Override
+    public void onResult(View view) {
+        mView = view.findViewById(mResId);
+        mViewStub = null;
+    }
+
+    /**
+     * @return the {@link View} encapsulated by this provider or null (if the view has not been
+     * inflated yet).
+     */
+    @Nullable
+    public T get() {
+        return mView;
+    }
+
+    /**
+     * @param resId resource id of the {@link View} that the returned provider would
+     *              encapsulate.
+     * @param <E> type of the {@link View} that the returned provider would encapsulate
+     * @return a provider for a {@link View} with resource id {@param resId} that is in the view
+     * hierarchy of the {@link View} encapsulated by this provider.
+     */
+    public <E extends View> AsyncViewProvider<E> getChildProvider(int resId) {
+        if (mView != null) {
+            return new AsyncViewProvider<>(mView.findViewById(resId));
+        }
+        return of(mViewStub, resId);
+    }
+
+    /**
+     * Add a callback that would be run (on the UI thread) once the {@link View} encapsulated by
+     * this provider is inflated. The callback runs immediately (blocking) if the view has
+     * already been inflated.
+     */
+    public void whenLoaded(Callback<T> callback) {
+        ThreadUtils.assertOnUiThread();
+        if (mDestroyed) return;
+        if (mView != null) {
+            // fire right now if view already inflated.
+            callback.onResult(mView);
+        } else {
+            mViewStub.addOnInflateListener((View view) -> {
+                if (mDestroyed) return;
+                // listeners are called in order so mView should be set correctly at this point.
+                callback.onResult(mView);
+            });
+        }
+    }
+
+    public void destroy() {
+        mDestroyed = true;
+        mView = null;
+        mViewStub = null;
+    }
+}
diff --git a/ui/android/java/src/org/chromium/ui/AsyncViewStub.java b/ui/android/java/src/org/chromium/ui/AsyncViewStub.java
new file mode 100644
index 0000000..9451822
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/AsyncViewStub.java
@@ -0,0 +1,153 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.v4.view.AsyncLayoutInflater;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import org.chromium.base.Callback;
+import org.chromium.base.ObserverList;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.TraceEvent;
+
+/**
+ * An implementation of ViewStub that inflates the view in a background thread. Callbacks are still
+ * called on the UI thread.
+ */
+public class AsyncViewStub extends View implements AsyncLayoutInflater.OnInflateFinishedListener {
+    private int mLayoutResource;
+    private View mInflatedView;
+
+    private static AsyncLayoutInflater sAsyncLayoutInflater;
+
+    private final ObserverList<Callback<View>> mListeners = new ObserverList<>();
+
+    public AsyncViewStub(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AsyncViewStub);
+        mLayoutResource = a.getResourceId(R.styleable.AsyncViewStub_layout, 0);
+        a.recycle();
+
+        setVisibility(GONE);
+        setWillNotDraw(true);
+
+        if (sAsyncLayoutInflater == null) {
+            sAsyncLayoutInflater = new AsyncLayoutInflater(getContext());
+        }
+    }
+
+    /**
+     * Specifies the layout resource to inflate when {@link #inflate(boolean)} is invoked. The View
+     * created by inflating the layout resource is used to replace this AsyncViewStub in its parent.
+     *
+     * @param layoutResource A valid layout resource identifier (different from 0.)
+     */
+    public void setLayoutResource(int layoutResource) {
+        mLayoutResource = layoutResource;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(0, 0);
+    }
+
+    @SuppressLint("MissingSuperCall")
+    @Override
+    public void draw(Canvas canvas) {}
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {}
+
+    @Override
+    public void onInflateFinished(@NonNull View view, int resId, ViewGroup parent) {
+        mInflatedView = view;
+        replaceSelfWithView(view, parent);
+        callListeners(view, resId, parent);
+    }
+
+    /**
+     * Starts background inflation for the stub, the AsyncViewStub must be attached to the window
+     * (ie have a parent) before you call inflate on it. Must be called on the UI thread.
+     * @param onBackgroundThread if inflation should be tried on a background thread first, this is
+     *                           used for A/B testing.
+     */
+    public void inflate(boolean onBackgroundThread) {
+        try (TraceEvent te = TraceEvent.scoped("AsyncViewStub.inflate")) {
+            ThreadUtils.assertOnUiThread();
+            final ViewParent viewParent = getParent();
+            assert viewParent != null;
+            assert viewParent instanceof ViewGroup;
+            assert mLayoutResource != 0;
+            if (onBackgroundThread) {
+                // AsyncLayoutInflater uses its own thread and cannot inflate <merge> elements. It
+                // might be a good idea to write our own version to use our scheduling primitives
+                // and to handle <merge> inflations.
+                sAsyncLayoutInflater.inflate(mLayoutResource, (ViewGroup) viewParent, this);
+            } else {
+                ViewGroup inflatedView =
+                        (ViewGroup) LayoutInflater.from(getContext())
+                                .inflate(mLayoutResource, (ViewGroup) viewParent, false);
+                onInflateFinished(inflatedView, mLayoutResource, (ViewGroup) viewParent);
+            }
+        }
+    }
+
+    private void callListeners(View view, int resId, ViewGroup parent) {
+        try (TraceEvent te = TraceEvent.scoped("AsyncViewStub.callListeners")) {
+            ThreadUtils.assertOnUiThread();
+            for (Callback<View> listener : mListeners) {
+                listener.onResult(view);
+            }
+            mListeners.clear();
+        }
+    }
+
+    /**
+     * This should only be used by {@link AsyncViewProvider}, use {@link
+     * AsyncViewProvider#whenLoaded} instead.
+     *
+     * Adds listener that gets called once the view is inflated and added to the view hierarchy. The
+     * listeners are called on the UI thread. This method can only be called on the UI thread.
+     *
+     * @param listener the listener to add.
+     */
+    void addOnInflateListener(Callback<View> listener) {
+        ThreadUtils.assertOnUiThread();
+        if (mInflatedView != null) {
+            listener.onResult(mInflatedView);
+        } else {
+            mListeners.addObserver(listener);
+        }
+    }
+
+    /**
+     * @return the inflated view or null if inflation is not complete yet.
+     */
+    View getInflatedView() {
+        return mInflatedView;
+    }
+
+    private void replaceSelfWithView(View view, ViewGroup parent) {
+        try (TraceEvent te = TraceEvent.scoped("AsyncViewStub.replaceSelfWithView")) {
+            int index = parent.indexOfChild(this);
+            parent.removeViewInLayout(this);
+            final ViewGroup.LayoutParams layoutParams = getLayoutParams();
+            if (layoutParams != null) {
+                parent.addView(view, index, layoutParams);
+            } else {
+                parent.addView(view, index);
+            }
+        }
+    }
+}
diff --git a/ui/android/junit/res/layout/inflated_view.xml b/ui/android/junit/res/layout/inflated_view.xml
new file mode 100644
index 0000000..bb5678a4
--- /dev/null
+++ b/ui/android/junit/res/layout/inflated_view.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/inflated_view"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    />
diff --git a/ui/android/junit/res/layout/main_view.xml b/ui/android/junit/res/layout/main_view.xml
new file mode 100644
index 0000000..41549d83
--- /dev/null
+++ b/ui/android/junit/res/layout/main_view.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:orientation="horizontal" >
+
+  <org.chromium.ui.AsyncViewStub
+      android:id="@+id/view_stub"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      />
+
+  <ImageView
+      android:id="@+id/pre_inflated_view"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      />
+
+</LinearLayout>
diff --git a/ui/android/junit/src/org/chromium/ui/AsyncViewProviderTest.java b/ui/android/junit/src/org/chromium/ui/AsyncViewProviderTest.java
new file mode 100644
index 0000000..17c07a0
--- /dev/null
+++ b/ui/android/junit/src/org/chromium/ui/AsyncViewProviderTest.java
@@ -0,0 +1,130 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.shadows.ShadowAsyncLayoutInflater;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests logic in the AsyncViewProvider class.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowAsyncLayoutInflater.class})
+public class AsyncViewProviderTest {
+    private LinearLayout mRoot;
+    private AsyncViewStub mAsyncViewStub;
+    private AsyncViewProvider<View> mAsyncViewProvider;
+    private final AtomicInteger mEventCount = new AtomicInteger();
+    private static final int MAIN_LAYOUT_RESOURCE_ID = org.chromium.test.ui.R.layout.main_view;
+    private static final int INFLATE_LAYOUT_RESOURCE_ID =
+            org.chromium.test.ui.R.layout.inflated_view;
+    private static final int STUB_ID = org.chromium.test.ui.R.id.view_stub;
+    private static final int INFLATED_VIEW_ID = org.chromium.test.ui.R.id.inflated_view;
+    private static final int PREINFLATED_VIEW_ID = org.chromium.test.ui.R.id.pre_inflated_view;
+
+    @Before
+    public void setUp() {
+        mRoot = (LinearLayout) LayoutInflater.from(RuntimeEnvironment.application)
+                        .inflate(MAIN_LAYOUT_RESOURCE_ID, null);
+        mAsyncViewStub = mRoot.findViewById(STUB_ID);
+        mAsyncViewStub.setLayoutResource(INFLATE_LAYOUT_RESOURCE_ID);
+        mAsyncViewProvider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
+        mAsyncViewStub.setId(STUB_ID);
+        mEventCount.set(0);
+    }
+
+    @Test
+    public void testCreatesUnloadedProviderIfNotInflated() {
+        AsyncViewProvider provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
+        assertNull(provider.get());
+    }
+
+    @Test
+    public void testCreatesLoadedProviderIfInflated() {
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        AsyncViewProvider provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
+        assertNotNull(provider.get());
+    }
+
+    @Test
+    public void testCreatesUnloadedProviderUsingResourceIds() {
+        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, STUB_ID, INFLATED_VIEW_ID);
+        assertNull(provider.get());
+    }
+
+    @Test
+    public void testCreatesLoadedProviderUsingResourceIds() {
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, STUB_ID, INFLATED_VIEW_ID);
+        assertNotNull(provider.get());
+    }
+
+    @Test
+    public void testCreatesLoadedProviderUsingResourceIdsWithoutAsyncViewStub() {
+        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, 0, PREINFLATED_VIEW_ID);
+        assertNotNull(provider.get());
+        assertTrue(provider.get() instanceof ImageView);
+    }
+
+    @Test
+    public void testRunsCallbackImmediatelyIfLoaded() {
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        AsyncViewProvider<View> provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
+        assertEquals(mEventCount.get(), 0);
+        provider.whenLoaded((View v) -> { mEventCount.incrementAndGet(); });
+        assertEquals(mEventCount.get(), 1);
+        provider.whenLoaded((View v) -> { mEventCount.incrementAndGet(); });
+        assertEquals(mEventCount.get(), 2);
+    }
+
+    @Test
+    public void testCallsListenersOnUiThread() {
+        mAsyncViewProvider.whenLoaded((View v) -> {
+            assertTrue(ThreadUtils.runningOnUiThread());
+            mEventCount.incrementAndGet();
+        });
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        // ensure callback gets called.
+        assertEquals(mEventCount.get(), 1);
+    }
+
+    @Test
+    public void testCallsListenersInOrder() {
+        mAsyncViewProvider.whenLoaded(
+                (View v) -> { assertEquals(mEventCount.incrementAndGet(), 1); });
+        mAsyncViewProvider.whenLoaded(
+                (View v) -> { assertEquals(mEventCount.incrementAndGet(), 2); });
+        mAsyncViewProvider.whenLoaded(
+                (View v) -> { assertEquals(mEventCount.decrementAndGet(), 1); });
+        assertEquals(mEventCount.get(), 0);
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        assertEquals(mEventCount.get(), 1);
+    }
+}
\ No newline at end of file
diff --git a/ui/android/junit/src/org/chromium/ui/AsyncViewStubTest.java b/ui/android/junit/src/org/chromium/ui/AsyncViewStubTest.java
new file mode 100644
index 0000000..4f343d8f
--- /dev/null
+++ b/ui/android/junit/src/org/chromium/ui/AsyncViewStubTest.java
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.shadows.ShadowAsyncLayoutInflater;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests logic in the AsyncViewStub class.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowAsyncLayoutInflater.class})
+public class AsyncViewStubTest {
+    private AsyncViewStub mAsyncViewStub;
+    private final AtomicInteger mEventCount = new AtomicInteger();
+    private static final int MAIN_LAYOUT_RESOURCE_ID = org.chromium.test.ui.R.layout.main_view;
+    private static final int INFLATE_LAYOUT_RESOURCE_ID =
+            org.chromium.test.ui.R.layout.inflated_view;
+    private static final int STUB_ID = org.chromium.test.ui.R.id.view_stub;
+
+    @Before
+    public void setUp() {
+        LinearLayout mainView = (LinearLayout) LayoutInflater.from(RuntimeEnvironment.application)
+                                        .inflate(MAIN_LAYOUT_RESOURCE_ID, null);
+        mAsyncViewStub = mainView.findViewById(STUB_ID);
+        mAsyncViewStub.setLayoutResource(INFLATE_LAYOUT_RESOURCE_ID);
+        mEventCount.set(0);
+    }
+
+    @Test
+    public void testCallsListenersOnUiThread() {
+        mAsyncViewStub.addOnInflateListener((View v) -> {
+            assertTrue(ThreadUtils.runningOnUiThread());
+            mEventCount.incrementAndGet();
+        });
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        // ensure callback gets called.
+        assertEquals(mEventCount.get(), 1);
+    }
+
+    @Test
+    public void testCallsListenersInOrder() {
+        mAsyncViewStub.addOnInflateListener(
+                (View v) -> { assertEquals(mEventCount.incrementAndGet(), 1); });
+        mAsyncViewStub.addOnInflateListener(
+                (View v) -> { assertEquals(mEventCount.incrementAndGet(), 2); });
+        mAsyncViewStub.addOnInflateListener(
+                (View v) -> { assertEquals(mEventCount.decrementAndGet(), 1); });
+        assertEquals(mEventCount.get(), 0);
+        mAsyncViewStub.inflate(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        assertEquals(mEventCount.get(), 1);
+    }
+}
\ No newline at end of file
diff --git a/ui/android/junit/src/org/chromium/ui/shadows/ShadowAsyncLayoutInflater.java b/ui/android/junit/src/org/chromium/ui/shadows/ShadowAsyncLayoutInflater.java
new file mode 100644
index 0000000..0eb8472
--- /dev/null
+++ b/ui/android/junit/src/org/chromium/ui/shadows/ShadowAsyncLayoutInflater.java
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui.shadows;
+
+import android.support.annotation.LayoutRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.view.AsyncLayoutInflater;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Shadow implementation of AsyncLayoutInflater that inflates on the UI thread then posts the
+ * callback on the UI thread delayed.
+ */
+@Implements(AsyncLayoutInflater.class)
+public class ShadowAsyncLayoutInflater {
+    @Implementation
+    public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
+            @NonNull AsyncLayoutInflater.OnInflateFinishedListener callback) {
+        View inflatedView = LayoutInflater.from(parent.getContext()).inflate(resid, parent, false);
+        ThreadUtils.postOnUiThreadDelayed(
+                () -> callback.onInflateFinished(inflatedView, inflatedView.getId(), parent), 500);
+    }
+}
\ No newline at end of file
diff --git a/ui/aura/client/screen_position_client.h b/ui/aura/client/screen_position_client.h
index a302d1c9..24e22be 100644
--- a/ui/aura/client/screen_position_client.h
+++ b/ui/aura/client/screen_position_client.h
@@ -53,7 +53,7 @@
 AURA_EXPORT ScreenPositionClient* GetScreenPositionClient(
     const Window* root_window);
 
-}  // namespace clients
+}  // namespace client
 }  // namespace aura
 
 #endif  // UI_AURA_SCREEN_POSITION_CLIENT_H_
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 9786d36..47e7e52 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -1104,13 +1104,10 @@
     InFlightBoundsChange bounds_change(this, window, bounds, local_surface_id);
     InFlightChange* current_change =
         GetOldestInFlightChangeMatching(bounds_change);
-    if (current_change) {
+    if (current_change)
       current_change->SetRevertValueFrom(bounds_change);
-    } else {
-      const gfx::Rect& window_bounds = window->GetWindow()->bounds();
-      if (window_bounds != bounds)
-        SetWindowBoundsFromServer(window, bounds, local_surface_id);
-    }
+    else if (window->GetWindow()->GetBoundsInScreen() != bounds)
+      SetWindowBoundsFromServer(window, bounds, local_surface_id);
   }
 
   // There is currently no API to bulk set properties, so we iterate over each
diff --git a/ui/aura/mus/window_tree_host_mus_init_params.cc b/ui/aura/mus/window_tree_host_mus_init_params.cc
index a882d81..6c876d4 100644
--- a/ui/aura/mus/window_tree_host_mus_init_params.cc
+++ b/ui/aura/mus/window_tree_host_mus_init_params.cc
@@ -61,9 +61,8 @@
     params.display_id =
         display::Screen::GetScreen()->GetDisplayMatching(bounds_in_screen).id();
   } else {
-    // TODO(jamescook): This should probably be the display for new windows,
-    // but that information isn't available at this level.
-    params.display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+    params.display_id =
+        display::Screen::GetScreen()->GetDisplayForNewWindows().id();
   }
 
   // Pass |properties| to CreateWindowPortForTopLevel() so that |properties|
diff --git a/ui/aura/window_targeter.cc b/ui/aura/window_targeter.cc
index c40ef77..fbf6f6f 100644
--- a/ui/aura/window_targeter.cc
+++ b/ui/aura/window_targeter.cc
@@ -8,10 +8,13 @@
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/event_client.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/events/event_target.h"
 #include "ui/events/event_target_iterator.h"
 
@@ -120,8 +123,16 @@
     if (consumer)
       return static_cast<Window*>(consumer);
 
-    // If the initial touch is outside the root window, target the root.
-    if (!root_window->bounds().Contains(event.root_location()))
+    // If the initial touch is outside the window's display, target the root.
+    // This is used for bezel gesture events (eg. swiping in from screen edge).
+    display::Display display =
+        display::Screen::GetScreen()->GetDisplayNearestWindow(root_window);
+    gfx::Point screen_location = event.root_location();
+    if (client::GetScreenPositionClient(root_window)) {
+      client::GetScreenPositionClient(root_window)
+          ->ConvertPointToScreen(root_window, &screen_location);
+    }
+    if (!display.bounds().Contains(screen_location))
       return root_window;
   }
 
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 73c038e3..319c2bd 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -47,3 +47,9 @@
     "video_player/js/cast:closure_compile",
   ]
 }
+
+group("unit_test_data") {
+  deps = [
+    "gallery/js/image_editor:unit_tests",
+  ]
+}
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index ec78ae0..4807d02 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -429,6 +429,7 @@
    */
   this.lastHostedFilesDisabled_ = null;
 
+  this.hideAndroidDownload();
   chrome.fileManagerPrivate.onPreferencesChanged.addListener(
       this.onPreferencesChanged_.bind(this));
   this.onPreferencesChanged_();
@@ -535,6 +536,23 @@
 };
 
 /**
+ * Sets up a filter to hide /Download directory in 'Play files' volume.
+ *
+ * "Play files/Download" is an alias to Chrome OS's Downloads volume. It is
+ * convenient in Android file picker, but can be confusing in Chrome OS Files
+ * app. This function adds a filter to hide the Android's /Download.
+ */
+FileFilter.prototype.hideAndroidDownload = function() {
+  this.addFilter('android_download', entry => {
+    if (entry.filesystem && entry.filesystem.name === 'android_files' &&
+        entry.fullPath === '/Download') {
+      return false;
+    }
+    return true;
+  });
+};
+
+/**
  * @param {Entry} entry File entry.
  * @return {boolean} True if the file should be shown, false otherwise.
  */
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_dispatcher_mock_deps.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_dispatcher_mock_deps.js
new file mode 100644
index 0000000..ebea153
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_dispatcher_mock_deps.js
@@ -0,0 +1,7 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// importScripts is used in metadata_dispatcher.js which is designed to work
+// inside SharedWorker.
+function importScripts(arg1) {}
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
index 1fb63e7..2dede3f 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -135,6 +135,7 @@
   VolumeManagerCommon.VolumeType.REMOVABLE,
   VolumeManagerCommon.VolumeType.ANDROID_FILES,
   VolumeManagerCommon.VolumeType.CROSTINI,
+  VolumeManagerCommon.VolumeType.MEDIA_VIEW,
 ];
 
 /**
diff --git a/ui/file_manager/gallery/js/image_editor/BUILD.gn b/ui/file_manager/gallery/js/image_editor/BUILD.gn
index 9a2e4a9..52fffc9 100644
--- a/ui/file_manager/gallery/js/image_editor/BUILD.gn
+++ b/ui/file_manager/gallery/js/image_editor/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
+import("//ui/file_manager/js_unit_tests.gni")
 
 js_type_check("closure_compile") {
   deps = [
@@ -75,6 +76,7 @@
 js_library("exif_encoder_unittest") {
   deps = [
     ":exif_encoder",
+    ":test_util",
     "../../../file_manager/foreground/js/metadata:exif_parser",
   ]
 }
@@ -145,6 +147,7 @@
 js_library("image_encoder_unittest") {
   deps = [
     ":image_encoder",
+    ":test_util",
     "../../../file_manager/common/js:unittest_util",
     "../../../file_manager/foreground/js/metadata:metadata_parser",
   ]
@@ -216,3 +219,12 @@
     "//ui/webui/resources/js/cr:event_target",
   ]
 }
+
+js_unit_tests("unit_tests") {
+  deps = [
+    ":exif_encoder_unittest",
+    ":image_encoder_unittest",
+    ":image_view_unittest",
+  ]
+  mocks = [ "../../../file_manager/foreground/js/metadata/metadata_dispatcher_mock_deps.js" ]
+}
diff --git a/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html b/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html
deleted file mode 100644
index 3016f41..0000000
--- a/ui/file_manager/gallery/js/image_editor/exif_encoder_unittest.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<!-- Copyright 2014 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.
-  -->
-<html>
-<body>
-
-<script type="text/javascript">
-  // importScripts is used in metadata_dispatcher.js which is designed to work inside SharedWorker.
-  function importScripts(arg1) {}
-</script>
-<script src="../../../../webui/resources/js/assert.js"></script>
-
-<script src="../../../file_manager/foreground/js/metadata/byte_reader.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_parser.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_dispatcher.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/exif_parser.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/exif_constants.js"></script>
-
-<script src="image_encoder.js"></script>
-<script src="exif_encoder.js"></script>
-
-<script src="test_util.js"></script>
-<script src="exif_encoder_unittest.js"></script>
-
-</body>
-</html>
diff --git a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html b/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html
deleted file mode 100644
index 0a527331..0000000
--- a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<!-- Copyright 2014 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.
-  -->
-<html>
-<body>
-
-<script src="../../../../webui/resources/js/assert.js"></script>
-
-<script src="../../../file_manager/common/js/unittest_util.js"></script>
-
-<script src="image_util.js"></script>
-<script src="image_encoder.js"></script>
-
-<script src="test_util.js"></script>
-<script src="image_encoder_unittest.js"></script>
-
-</body>
-</html>
diff --git a/ui/file_manager/gallery/js/image_editor/image_view_unittest.html b/ui/file_manager/gallery/js/image_editor/image_view_unittest.html
deleted file mode 100644
index f2a9eae..0000000
--- a/ui/file_manager/gallery/js/image_editor/image_view_unittest.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<!-- Copyright 2014 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.
-  -->
-<html>
-<body>
-
-<!-- Should be loaded before volume_manager.js -->
-<script src="../../file_manager/common/js/volume_manager_common.js"></script>
-
-<!-- Viewport deps -->
-<script src="../../../../webui/resources/js/assert.js"></script>
-<script src="../../../../webui/resources/js/cr.js"></script>
-<script src="../../../../webui/resources/js/cr/event_target.js"></script>
-
-<!-- MetadataModel deps -->
-<script src="../../../file_manager/foreground/js/metadata/metadata_cache_set.js"></script>
-<script src="../../../common/js/lru_cache.js"></script>
-<script src="../../../common/js/unittest_util.js"></script>
-<script src="../../../common/js/util.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_cache_item.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_item.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_model.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_provider.js"></script>
-<script src="../../../file_manager/foreground/js/metadata/metadata_request.js"></script>
-
-<!-- Metrics deps -->
-<script src="../../../file_manager/test/js/chrome_api_test_impl.js"></script>
-<script src="../../../file_manager/common/js/metrics_base.js"></script>
-<script src="../../../file_manager/common/js/metrics.js"></script>
-<script src="../../../file_manager/foreground/js/metrics_start.js"></script>
-
-<!-- Others -->
-<script src="../../../file_manager/common/js/file_type.js"></script>
-<script src="../../../file_manager/common/js/mock_entry.js"></script>
-<script src="../../../file_manager/foreground/js/thumbnail_loader.js"></script>
-
-<script src="../gallery_item.js"></script>
-<script src="viewport.js"></script>
-<script src="image_buffer.js"></script>
-<script src="image_util.js"></script>
-<script src="image_loader.js"></script>
-<script src="image_view.js"></script>
-<script src="image_view_unittest.js"></script>
-
-</body>
-</html>
diff --git a/ui/file_manager/integration_tests/file_manager/delete.js b/ui/file_manager/integration_tests/file_manager/delete.js
index 873f5b4..684672f 100644
--- a/ui/file_manager/integration_tests/file_manager/delete.js
+++ b/ui/file_manager/integration_tests/file_manager/delete.js
@@ -6,25 +6,25 @@
  * Tests that the Delete menu item is disabled if no entry is selected.
  */
 testcase.deleteMenuItemNoEntrySelected = function() {
+  const contextMenu = '#file-context-menu:not([hidden])';
+
   testPromise(setupAndWaitUntilReady(null, RootPath.DOWNLOADS).then(
       function(results) {
         var windowId = results.windowId;
-        // Right click the list without selecting an item.
-        return remoteCall.callRemoteTestUtil(
-            'fakeMouseRightClick', windowId, ['list.list']
-            ).then(function(result) {
-          chrome.test.assertTrue(result);
-
-          // Wait until the context menu is shown.
-          return remoteCall.waitForElement(
-              windowId,
-              '#file-context-menu:not([hidden])');
-        }).then(function() {
-          // Assert that delete command is disabled.
-          return remoteCall.waitForElement(
-              windowId,
-              'cr-menu-item[command="#delete"][disabled="disabled"]');
-        });
+        // Right click the list without selecting an entry.
+        return remoteCall
+            .callRemoteTestUtil('fakeMouseRightClick', windowId, ['list.list'])
+            .then(function(result) {
+              chrome.test.assertTrue(!!result, 'fakeMouseRightClick failed');
+              // Wait until the context menu is shown.
+              return remoteCall.waitForElement(windowId, contextMenu);
+            })
+            .then(function() {
+              // Assert the menu delete command is disabled.
+              const deleteDisabled = '[command="#delete"][disabled="disabled"]';
+              return remoteCall.waitForElement(
+                  windowId, contextMenu + ' ' + deleteDisabled);
+            });
       }));
 };
 
@@ -51,35 +51,36 @@
       function(results) {
         var windowId = results.windowId;
         // Confirm entries in the directory before the deletion.
-        //
-        // Ignore last modified time since file manager sometimes fails to get
-        // last modified time of files.
-        // TODO(yawano): Fix the root cause and remove this temporary fix.
-        return remoteCall.waitForFiles(windowId, beforeDeletion,
-            {ignoreLastModifiedTime: true}).then(function() {
-          // Select My Desktop Background.png
-          return remoteCall.callRemoteTestUtil(
-              'selectFile', windowId, ['My Desktop Background.png']);
-        }).then(function(result) {
-          chrome.test.assertTrue(result);
-
-          // Click delete button in the toolbar.
-          return remoteCall.callRemoteTestUtil(
-              'fakeMouseClick', windowId, ['button#delete-button']);
-        }).then(function(result) {
-          chrome.test.assertTrue(result);
-
-          // Confirm that the confirmation dialog is shown.
-          return remoteCall.waitForElement(
-              windowId, '.cr-dialog-container.shown');
-        }).then(function() {
-          // Press delete button.
-          return remoteCall.callRemoteTestUtil(
-              'fakeMouseClick', windowId, ['button.cr-dialog-ok']);
-        }).then(function() {
-          // Confirm the file is removed.
-          return remoteCall.waitForFiles(windowId, afterDeletion,
-              {ignoreLastModifiedTime: true});
-        });
+        return remoteCall
+            .waitForFiles(
+                windowId, beforeDeletion, {ignoreLastModifiedTime: true})
+            .then(function() {
+              // Select My Desktop Background.png
+              return remoteCall.callRemoteTestUtil(
+                  'selectFile', windowId, ['My Desktop Background.png']);
+            })
+            .then(function(result) {
+              chrome.test.assertTrue(result);
+              // Click delete button in the toolbar.
+              return remoteCall.callRemoteTestUtil(
+                  'fakeMouseClick', windowId, ['button#delete-button']);
+            })
+            .then(function(result) {
+              chrome.test.assertTrue(result);
+              // Confirm that the confirmation dialog is shown.
+              return remoteCall.waitForElement(
+                  windowId, '.cr-dialog-container.shown');
+            })
+            .then(function() {
+              // Press delete button.
+              return remoteCall.callRemoteTestUtil(
+                  'fakeMouseClick', windowId, ['button.cr-dialog-ok']);
+            })
+            .then(function(result) {
+              chrome.test.assertTrue(!!result, 'fakeMouseClick failed');
+              // Confirm the file is removed.
+              return remoteCall.waitForFiles(
+                  windowId, afterDeletion, {ignoreLastModifiedTime: true});
+            });
       }));
 };
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index 08da11a..86a90e0 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -121,19 +121,23 @@
  * Clicks context menu item of id in directory tree.
  */
 function clickDirectoryTreeContextMenuItem(windowId, path, id) {
+  const contextMenu = '#directory-tree-context-menu:not([hidden])';
+
   return remoteCall.callRemoteTestUtil('focus', windowId,
-      [`[full-path-for-testing="${path}"]`]).then(function() {
+      [`[full-path-for-testing="${path}"]`]).then(function(result) {
+    chrome.test.assertTrue(!!result, 'focus failed');
     // Right click photos directory.
     return remoteCall.callRemoteTestUtil('fakeMouseRightClick', windowId,
         [`[full-path-for-testing="${path}"]`]);
-  }).then(function() {
-    // Wait for context menu.
+  }).then(function(result) {
+    chrome.test.assertTrue(!!result, 'fakeMouseRightClick failed');
+    // Check: context menu item |id| should be shown enabled.
     return remoteCall.waitForElement(windowId,
-        `#directory-tree-context-menu > [command="#${id}"]:not([disabled])`);
+        `${contextMenu} [command="#${id}"]:not([disabled])`);
   }).then(function() {
-    // Click menu item.
+    // Click the menu item specified by |id|.
     return remoteCall.callRemoteTestUtil('fakeMouseClick', windowId,
-        [`#directory-tree-context-menu > [command="#${id}"]`]);
+        [`${contextMenu} [command="#${id}"]`]);
   });
 }
 
diff --git a/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js b/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
index 6657ab6..0102473 100644
--- a/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
+++ b/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
@@ -23,61 +23,37 @@
     },
     // Wait for the share button.
     function(result) {
-      chrome.test.assertTrue(result);
+      chrome.test.assertTrue(!!result);
       remoteCall.waitForElement(appId, '#share-menu-button:not([disabled])')
           .then(this.next);
     },
-    // Open share options menu
+    // Click the share button to open share menu.
     function(result) {
       chrome.test.assertTrue(!!result);
       remoteCall.callRemoteTestUtil(
           'fakeMouseClick', appId, ['#share-menu-button'], this.next);
     },
-    // Wait until the "Share with others" item is shown.
-    function(result) {
-      chrome.test.assertTrue(result);
-      remoteCall
-          .waitForElement(
-              appId, 'cr-menu-item[command="#share"]:not([disabled]')
-          .then(this.next);
-    },
-    // Invoke the share dialog.
+    // Check: the "Share with others" menu item should be shown enabled.
     function(result) {
       chrome.test.assertTrue(!!result);
-      remoteCall.callRemoteTestUtil(
-          'fakeMouseClick', appId, ['cr-menu-item[command="#share"]'],
-          this.next);
+      const shareMenuItem =
+          '#share-menu:not([hidden]) [command="#share"]:not([disabled])';
+      remoteCall.waitForElement(appId, shareMenuItem).then(this.next);
     },
-    // Wait until the share dialog's contents are shown.
+    // Click the "Share with others" menu item to open the share dialog.
     function(result) {
-      chrome.test.assertTrue(result);
+      chrome.test.assertTrue(!!result);
+      const item = ['#share-menu [command="#share"]'];
+      remoteCall.callRemoteTestUtil('fakeMouseClick', appId, item, this.next);
+    },
+    // Wait until the share dialog's (mocked) content is shown.
+    function(result) {
+      chrome.test.assertTrue(!!result);
       remoteCall.waitForElement(appId, '.share-dialog-webview-wrapper.loaded')
           .then(this.next);
     },
-    function(result) {
-      chrome.test.assertTrue(!!result);
-      repeatUntil(function() {
-        return remoteCall
-            .callRemoteTestUtil(
-                'queryAllElements', appId,
-                ['.share-dialog-webview-wrapper.loaded', ['width', 'height']])
-            .then(function(elements) {
-              // TODO(mtomasz): Fix the wrong geometry of the share dialog.
-              // return elements[0] &&
-              //     elements[0].styles.width === '350px' &&
-              //     elements[0].styles.height === '250px' ?
-              //     undefined :
-              //     pending('Dialog wrapper is currently %j. ' +
-              //             'but should be: 350x250',
-              //             elements[0]);
-              return elements[0] ?
-                  undefined :
-                  pending(caller, 'The share dialog is not found.');
-            });
-      }).then(this.next);
-    },
     // Wait until the share dialog's contents are shown.
-    function(result) {
+    function() {
       remoteCall.callRemoteTestUtil(
           'executeScriptInWebView', appId,
           [
@@ -122,7 +98,7 @@
     },
     // Wait for the file to be selected.
     function(result) {
-      chrome.test.assertTrue(result);
+      chrome.test.assertTrue(!!result);
       remoteCall.waitForElement(appId, '.table-row[selected]').then(this.next);
     },
     // Right-click on the file.
@@ -133,7 +109,7 @@
     },
     // Wait for the context menu to appear.
     function(result) {
-      chrome.test.assertTrue(result);
+      chrome.test.assertTrue(!!result);
       remoteCall.waitForElement(appId, '#file-context-menu:not([hidden])')
           .then(this.next);
     },
diff --git a/ui/file_manager/integration_tests/file_manager/tasks.js b/ui/file_manager/integration_tests/file_manager/tasks.js
index ff29903..dce4de1 100644
--- a/ui/file_manager/integration_tests/file_manager/tasks.js
+++ b/ui/file_manager/integration_tests/file_manager/tasks.js
@@ -194,13 +194,14 @@
                 'fakeMouseClick', windowId, ['#tasks']);
             // Wait for dropdown menu to show.
             return remoteCall.waitForElement(
-                windowId, '#tasks-menu cr-menu-item');
+                windowId, '#tasks-menu:not([hidden]) cr-menu-item');
           })
           .then(function(result) {
+            chrome.test.assertTrue(!!result);
             // Click on first menu item.
             remoteCall.callRemoteTestUtil(
                 'fakeMouseClick', windowId,
-                ['#tasks-menu cr-menu-item:nth-child(1)']);
+                ['#tasks-menu:not([hidden]) cr-menu-item:nth-child(1)']);
             // Wait dropdown menu to hide.
             return remoteCall.waitForElement(windowId, '#tasks-menu[hidden]');
           })
diff --git a/ui/file_manager/integration_tests/file_manager/zip_files.js b/ui/file_manager/integration_tests/file_manager/zip_files.js
index 9c014f2..b311ba2 100644
--- a/ui/file_manager/integration_tests/file_manager/zip_files.js
+++ b/ui/file_manager/integration_tests/file_manager/zip_files.js
@@ -186,7 +186,8 @@
       remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [zip], this.next);
     },
     // Check: a zip file should be created.
-    function() {
+    function(result) {
+      chrome.test.assertTrue(!!result, 'fakeMouseClick failed');
       const files = getZipSelectionFileListRowEntries();
       remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true})
           .then(this.next);
@@ -233,7 +234,8 @@
       remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [zip], this.next);
     },
     // Check: a zip file should be created.
-    function() {
+    function(result) {
+      chrome.test.assertTrue(!!result, 'fakeMouseClick failed');
       const files = getZipSelectionFileListRowEntries();
       remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true})
           .then(this.next);
@@ -305,7 +307,8 @@
       remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [zip], this.next);
     },
     // Check: a zip file should be created.
-    function() {
+    function(result) {
+      chrome.test.assertTrue(!!result, 'fakeMouseClick failed');
       const files = getZipSelectionFileListRowEntries();
       remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true})
           .then(this.next);
diff --git a/ui/file_manager/js_unit_test.py b/ui/file_manager/js_unit_test.py
new file mode 100644
index 0000000..351882f6
--- /dev/null
+++ b/ui/file_manager/js_unit_test.py
@@ -0,0 +1,78 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This script takes in a file created by js_library.py and any supplementary js
+files to build an html file used for js unit tests.
+"""
+
+from argparse import ArgumentParser
+
+def flatten(deps):
+  """
+  Recursively follows a list of dep files and returns source files in
+  dependency order. Ignores externs.
+  """
+  if len(deps) == 0:
+    return []
+  sources = []
+  moredeps = []
+  for d in deps:
+    with open(d, "r") as depfile:
+      assert depfile.readline(
+          ) == 'sources:\n', "Depfile parse error (expected 'sources:')."
+      line = depfile.readline()
+      while line != 'deps:\n':
+        assert line != '', "Depfile parse error (expected 'deps:')."
+        sources.append(line[:-1])
+        line = depfile.readline()
+      line = depfile.readline()
+      while line != 'externs:\n':
+        assert line != '', "Depfile parse error (expected 'externs:')."
+        moredeps.append(line[:-1])
+        line = depfile.readline()
+  return flatten(moredeps) + sources
+
+def main():
+  parser = ArgumentParser()
+  parser.add_argument('-i', '--input',
+                      help='Input dependency file generated by js_library.py')
+  parser.add_argument('-m', '--mocks', nargs='*', default=[],
+                      help='List of additional js files to load before others')
+  parser.add_argument('-o', '--output',
+                      help='Generated html output with flattened dependencies')
+  args = parser.parse_args()
+
+  alldeps = flatten([args.input])
+  uniquedeps = []
+  # No such thing as include guards, so do that here with a set.
+  seen = set()
+  for d in alldeps:
+    if d not in seen:
+      seen.add(d)
+      uniquedeps.append(d)
+  with open(args.output, 'w') as out:
+    out.write('<!DOCTYPE html>\n<html>\n<body>\n')
+    out.write(
+"""
+<script>
+// Basic include checker.
+window.addEventListener('error', function(e) {
+  if ((e.target instanceof HTMLScriptElement)) {
+    console.log('ERROR loading <script> element (does it exist?):\\n\\t' +
+                e.srcElement.src + '\\n\\tIncluded from: ' +
+                e.srcElement.baseURI);
+  }
+}, true /* useCapture */);
+</script>
+
+""")
+    for file in args.mocks:
+      out.write('<script src="%s"></script>\n' % (file))
+    for file in uniquedeps:
+      out.write('<script src="%s"></script>\n' % (file))
+    out.write('</body>\n</html>\n')
+
+if __name__ == '__main__':
+  main()
diff --git a/ui/file_manager/js_unit_tests.gni b/ui/file_manager/js_unit_tests.gni
new file mode 100644
index 0000000..0e4fc30
--- /dev/null
+++ b/ui/file_manager/js_unit_tests.gni
@@ -0,0 +1,58 @@
+# Copyright 2018 The Chromium Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Describes a list of js_library targets that will each have an html file
+# written listing all its (flattened) js dependencies, for loading as a test.
+# Must be declared after the js_library targets it depends on.
+#
+# Variables:
+#   deps:
+#     List of js_library targets to depend on
+#
+#   mocks:
+#     An optional list of .js files to load before any other scripts
+#
+# Example:
+#   js_unit_tests("folder_tests") {
+#     deps = [
+#       ":foo_unittest",
+#       ":bar_unittest",
+#       ":baz_unittest",
+#     ]
+#     mocks = [ "my_mocks.js" ]
+#   }
+
+template("js_unit_tests") {
+  html_gen_target_name = target_name + "_html_gen"
+  action_foreach(html_gen_target_name) {
+    script_path = "//ui/file_manager"
+    script = "$script_path/js_unit_test.py"
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "mocks",
+                           ])
+    sources = []
+    foreach(dep, deps) {
+      sources += get_target_outputs(dep)
+    }
+
+    outputs = [
+      "$target_gen_dir/{{source_name_part}}.html",
+    ]
+    args = [ "--output" ] + rebase_path(outputs, root_build_dir)
+    args += [ "--input" ] + [ "{{source}}" ]
+
+    if (defined(mocks)) {
+      args += [ "--mocks" ] + rebase_path(mocks, root_build_dir)
+      data = mocks
+    }
+  }
+  group(target_name) {
+    data = get_target_outputs(":$html_gen_target_name")
+    deps = [
+      ":$html_gen_target_name",
+    ]
+  }
+}
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc
index 3c7f114..c4ae1e2 100644
--- a/ui/gfx/color_utils.cc
+++ b/ui/gfx/color_utils.cc
@@ -188,6 +188,12 @@
     hsl->l = -1;
 }
 
+bool IsHSLShiftMeaningful(const HSL& hsl) {
+  // -1 in any channel is no-op, but additionally 0.5 is no-op for S/L.
+  return hsl.h != -1 && hsl.s != -1 && hsl.s != 0.5 && hsl.l != -1 &&
+         hsl.l != 0.5;
+}
+
 SkColor HSLShift(SkColor color, const HSL& shift) {
   SkAlpha alpha = SkColorGetA(color);
 
diff --git a/ui/gfx/color_utils.h b/ui/gfx/color_utils.h
index 35d2748..747ecbb 100644
--- a/ui/gfx/color_utils.h
+++ b/ui/gfx/color_utils.h
@@ -64,6 +64,10 @@
 // special value which indicates 'no change'.
 GFX_EXPORT void MakeHSLShiftValid(HSL* hsl);
 
+// Returns whether pasing |hsl| to HSLShift() would have any effect.  Assumes
+// |hsl| is a valid shift (as defined by MakeHSLShiftValid()).
+GFX_EXPORT bool IsHSLShiftMeaningful(const HSL& hsl);
+
 // HSL-Shift an SkColor. The shift values are in the range of 0-1, with the
 // option to specify -1 for 'no change'. The shift values are defined as:
 // hsl_shift[0] (hue): The absolute hue value - 0 and 1 map
diff --git a/ui/gfx/mac/display_icc_profiles.cc b/ui/gfx/mac/display_icc_profiles.cc
index 45bbb4b..3e0c359 100644
--- a/ui/gfx/mac/display_icc_profiles.cc
+++ b/ui/gfx/mac/display_icc_profiles.cc
@@ -35,6 +35,7 @@
 void DisplayICCProfiles::UpdateIfNeeded() {
   if (!needs_update_)
     return;
+  needs_update_ = false;
   map_.clear();
 
   // Always add Apple's sRGB profile.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 76fac948..1d4f863 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -780,6 +780,9 @@
 }
 
 gfx::Rect KeyboardController::GetWorkspaceOccludedBounds() const {
+  if (!enabled())
+    return gfx::Rect();
+
   const gfx::Rect visual_bounds_in_window(visual_bounds_in_screen_.size());
   const gfx::Rect occluded_bounds_in_window =
       container_behavior_->GetOccludedBounds(visual_bounds_in_window);
diff --git a/ui/message_center/views/message_popup_collection.cc b/ui/message_center/views/message_popup_collection.cc
index 607ba7c4..f68c257 100644
--- a/ui/message_center/views/message_popup_collection.cc
+++ b/ui/message_center/views/message_popup_collection.cc
@@ -44,6 +44,8 @@
     return;
   base::AutoReset<bool> reset(&is_updating_, true);
 
+  RemoveClosedPopupItems();
+
   if (animation_->is_animating()) {
     UpdateByAnimation();
     return;
@@ -93,6 +95,7 @@
   {
     base::AutoReset<bool> reset(&is_updating_, true);
 
+    RemoveClosedPopupItems();
     ResetHotMode();
     state_ = State::IDLE;
     animation_->End();
@@ -118,6 +121,13 @@
   Update();
 }
 
+void MessagePopupCollection::NotifyPopupClosed(MessagePopupView* popup) {
+  for (auto& item : popup_items_) {
+    if (item.popup == popup)
+      item.popup = nullptr;
+  }
+}
+
 void MessagePopupCollection::OnNotificationAdded(
     const std::string& notification_id) {
   Update();
@@ -131,6 +141,8 @@
 
 void MessagePopupCollection::OnNotificationUpdated(
     const std::string& notification_id) {
+  RemoveClosedPopupItems();
+
   // Find Notification object with |notification_id|.
   const auto& notifications = MessageCenter::Get()->GetPopupNotifications();
   auto it = notifications.begin();
@@ -462,7 +474,6 @@
     if (!item.is_animating)
       continue;
     item.popup->Close();
-    item.popup = nullptr;
   }
   RemoveClosedPopupItems();
 }
@@ -473,7 +484,6 @@
     if (item.popup->GetOpacity() > 0.0)
       continue;
     item.popup->Close();
-    item.popup = nullptr;
     removed = true;
   }
   RemoveClosedPopupItems();
@@ -486,7 +496,6 @@
     if (work_area.Contains(item.bounds))
       continue;
     item.popup->Close();
-    item.popup = nullptr;
   }
   RemoveClosedPopupItems();
 }
diff --git a/ui/message_center/views/message_popup_collection.h b/ui/message_center/views/message_popup_collection.h
index 4d6faa82..2b05ea8d 100644
--- a/ui/message_center/views/message_popup_collection.h
+++ b/ui/message_center/views/message_popup_collection.h
@@ -43,6 +43,9 @@
   // Notify the popup size is changed. Called from MessagePopupView.
   void NotifyPopupResized();
 
+  // Notify the popup is closed. Called from MessagePopupView.
+  void NotifyPopupClosed(MessagePopupView* popup);
+
   // MessageCenterObserver:
   void OnNotificationAdded(const std::string& notification_id) override;
   void OnNotificationRemoved(const std::string& notification_id,
diff --git a/ui/message_center/views/message_popup_collection_unittest.cc b/ui/message_center/views/message_popup_collection_unittest.cc
index 73dad0e4..b5046bd 100644
--- a/ui/message_center/views/message_popup_collection_unittest.cc
+++ b/ui/message_center/views/message_popup_collection_unittest.cc
@@ -902,4 +902,19 @@
   EXPECT_TRUE(work_area().Contains(r1));
 }
 
+TEST_F(MessagePopupCollectionTest, PopupWidgetClosedOutsideDuringFadeOut) {
+  std::string id = AddNotification();
+  AnimateUntilIdle();
+
+  MessageCenter::Get()->MarkSinglePopupAsShown(id, false);
+  AnimateToMiddle();
+
+  // On Windows it might be possible that the widget is closed outside
+  // MessagePopupCollection?  https://crbug.com/871199
+  GetPopup(id)->GetWidget()->CloseNow();
+  AnimateToEnd();
+
+  EXPECT_FALSE(IsAnimating());
+}
+
 }  // namespace message_center
diff --git a/ui/message_center/views/message_popup_view.cc b/ui/message_center/views/message_popup_view.cc
index 774e063..06454c3 100644
--- a/ui/message_center/views/message_popup_view.cc
+++ b/ui/message_center/views/message_popup_view.cc
@@ -62,26 +62,40 @@
   SetLayoutManager(std::make_unique<views::FillLayout>());
 }
 
-MessagePopupView::~MessagePopupView() = default;
+MessagePopupView::~MessagePopupView() {
+  popup_collection_->NotifyPopupClosed(this);
+}
 
 void MessagePopupView::UpdateContents(const Notification& notification) {
+  ui::AXNodeData old_data;
+  message_view_->GetAccessibleNodeData(&old_data);
   message_view_->UpdateWithNotification(notification);
   popup_collection_->NotifyPopupResized();
   if (notification.rich_notification_data()
           .should_make_spoken_feedback_for_popup_updates) {
-    NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
+    ui::AXNodeData new_data;
+    message_view_->GetAccessibleNodeData(&new_data);
+    if (old_data.GetStringAttribute(ax::mojom::StringAttribute::kName) !=
+        new_data.GetStringAttribute(ax::mojom::StringAttribute::kName))
+      NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
   }
 }
 
 float MessagePopupView::GetOpacity() const {
+  if (!GetWidget() || GetWidget()->IsClosed())
+    return 0.f;
   return GetWidget()->GetLayer()->opacity();
 }
 
 void MessagePopupView::SetPopupBounds(const gfx::Rect& bounds) {
+  if (!GetWidget() || GetWidget()->IsClosed())
+    return;
   GetWidget()->SetBounds(bounds);
 }
 
 void MessagePopupView::SetOpacity(float opacity) {
+  if (!GetWidget() || GetWidget()->IsClosed())
+    return;
   GetWidget()->SetOpacity(opacity);
 }
 
@@ -170,7 +184,7 @@
 
 void MessagePopupView::OnWorkAreaChanged() {
   views::Widget* widget = GetWidget();
-  if (!widget)
+  if (!widget || widget->IsClosed())
     return;
 
   gfx::NativeView native_view = widget->GetNativeView();
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index c298ac455..6c8dd7e 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -74,7 +74,14 @@
 
   // Create the opaque background that's above the view's shadow.
   background_view_ = new views::View();
-  UpdateCornerRadius(0, 0);
+
+  // ChromeOS rounds the corners of the message view. TODO(estade): should we do
+  // this for all platforms?
+  if (ShouldRoundMessageViewCorners())
+    UpdateCornerRadius(kNotificationCornerRadius, kNotificationCornerRadius);
+  else
+    UpdateCornerRadius(0, 0);
+
   AddChildView(background_view_);
 
   focus_painter_ = views::Painter::CreateSolidFocusPainter(
@@ -246,16 +253,6 @@
 
   // Background.
   background_view_->SetBoundsRect(content_bounds);
-
-  // ChromeOS rounds the corners of the message view. TODO(estade): should we do
-  // this for all platforms?
-  if (ShouldRoundMessageViewCorners()) {
-    gfx::Path path;
-    constexpr SkScalar kCornerRadius = SkIntToScalar(kNotificationCornerRadius);
-    path.addRoundRect(gfx::RectToSkRect(background_view_->GetLocalBounds()),
-                      kCornerRadius, kCornerRadius);
-    background_view_->set_clip_path(path);
-  }
 }
 
 const char* MessageView::GetClassName() const {
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index 674a9b7..827da47 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -13,11 +13,9 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#import "ui/accelerated_widget_mac/accelerated_widget_mac.h"
 #include "ui/accelerated_widget_mac/ca_transaction_observer.h"
 #include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
 #include "ui/base/ime/input_method_delegate.h"
-#include "ui/compositor/layer_owner.h"
 #import "ui/views/cocoa/bridged_native_widget_owner.h"
 #import "ui/views/cocoa/cocoa_mouse_capture_delegate.h"
 #import "ui/views/focus/focus_manager.h"
@@ -31,7 +29,6 @@
 
 namespace ui {
 class InputMethod;
-class RecyclableCompositorMac;
 }
 
 namespace views {
@@ -39,6 +36,7 @@
 class BridgedNativeWidgetTestApi;
 }
 
+class BridgedNativeWidgetHost;
 class CocoaMouseCapture;
 class CocoaWindowMoveLoop;
 class DragDropClientMac;
@@ -50,12 +48,9 @@
 // NativeWidgetMac to the Cocoa window. Behaves a bit like an aura::Window.
 class VIEWS_EXPORT BridgedNativeWidget
     : public ui::CATransactionCoordinator::PreCommitObserver,
-      public ui::LayerDelegate,
-      public ui::LayerOwner,
       public ui::internal::InputMethodDelegate,
       public CocoaMouseCaptureDelegate,
       public FocusChangeListener,
-      public ui::AcceleratedWidgetMacNSView,
       public BridgedNativeWidgetOwner,
       public DialogObserver {
  public:
@@ -75,8 +70,8 @@
   static gfx::Size GetWindowSizeForClientSize(NSWindow* window,
                                               const gfx::Size& size);
 
-  // Creates one side of the bridge. |parent| must not be NULL.
-  explicit BridgedNativeWidget(NativeWidgetMac* parent);
+  // Creates one side of the bridge. |host| and |parent| must not be NULL.
+  BridgedNativeWidget(BridgedNativeWidgetHost* host, NativeWidgetMac* parent);
   ~BridgedNativeWidget() override;
 
   // Initialize the bridge, "retains" ownership of |window|.
@@ -176,8 +171,6 @@
   // fullscreen or transitioning between fullscreen states.
   gfx::Rect GetRestoredBounds() const;
 
-  // Creates a ui::Compositor which becomes responsible for drawing the window.
-  void CreateLayer(ui::LayerType layer_type, bool translucent);
 
   // Updates |associated_views_| on NativeViewHost::Attach()/Detach().
   void SetAssociationForView(const views::View* view, NSView* native_view);
@@ -227,13 +220,24 @@
   bool ShouldRunCustomAnimationFor(
       Widget::VisibilityTransition transition) const;
 
-  // ui::CATransactionCoordinator::PreCommitObserver implementation
+  // ui::CATransactionCoordinator::PreCommitObserver:
   bool ShouldWaitInPreCommit() override;
   base::TimeDelta PreCommitTimeout() override;
 
-  // Overridden from ui::internal::InputMethodDelegate:
+  // ui::internal::InputMethodDelegate:
   ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override;
 
+  // views::BridgedNativeWidget:
+  // TODO(ccameron): Rename BridgedNativeWidget to BridgedNativeWidgetImpl, and
+  // make these methods be exposed via the BridgedNativeWidget interface.
+  // Initialize the view to display compositor output. This will send the
+  // current visibility and dimensions (and any future updates) to the
+  // BridgedNativeWidgetHost.
+  void InitCompositorView();
+
+  // Specify the content to draw in the NSView.
+  void SetCALayerParams(const gfx::CALayerParams& ca_layer_params);
+
  private:
   friend class test::BridgedNativeWidgetTestApi;
 
@@ -247,28 +251,17 @@
   // coordinate transformations are required from AppKit coordinates.
   gfx::Size GetClientAreaSize() const;
 
-  // Creates an owned ui::Compositor. For consistency, these functions reflect
-  // those in aura::WindowTreeHost.
-  void CreateCompositor();
-  void InitCompositor();
-  void DestroyCompositor();
-
   // Installs the NSView for hosting the composited layer.
   void AddCompositorSuperview();
 
   // Size the layer to match the client area bounds, taking into account display
   // scale factor.
-  void UpdateLayerProperties();
-
-  // Immediately return if there is a composited frame matching |size_in_dip|.
-  // Otherwise, asks ui::WindowResizeHelperMac to run tasks until a matching
-  // frame is ready, or a timeout occurs.
-  void MaybeWaitForFrame(const gfx::Size& size_in_dip);
+  void UpdateCompositorSizeAndScale();
 
   // Show the window using -[NSApp beginSheet:..], modal for the parent window.
   void ShowAsModalSheet();
 
-  // Overridden from CocoaMouseCaptureDelegate:
+  // CocoaMouseCaptureDelegate:
   void PostCapturedEvent(NSEvent* event) override;
   void OnMouseCaptureLost() override;
   NSWindow* GetWindow() const override;
@@ -277,21 +270,13 @@
   // Creates and attaches a new instance if not found.
   NSMutableDictionary* GetWindowProperties() const;
 
-  // Overridden from FocusChangeListener:
+  // FocusChangeListener:
   void OnWillChangeFocus(View* focused_before,
                          View* focused_now) override;
   void OnDidChangeFocus(View* focused_before,
                         View* focused_now) override;
 
-  // Overridden from ui::LayerDelegate:
-  void OnPaintLayer(const ui::PaintContext& context) override;
-  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
-                                  float new_device_scale_factor) override;
-
-  // Overridden from ui::AcceleratedWidgetMac:
-  void AcceleratedWidgetCALayerParamsUpdated() override;
-
-  // Overridden from BridgedNativeWidgetOwner:
+  // BridgedNativeWidgetOwner:
   NSWindow* GetNSWindow() override;
   gfx::Vector2d GetChildWindowOffset() const override;
   bool IsVisibleParent() const override;
@@ -303,9 +288,10 @@
   // Set |layer()| to be visible or not visible based on |window_visible_|. If
   // the layer is not visible, then lock the compositor, so we don't draw any
   // new frames.
-  void UpdateLayerVisibility();
+  void UpdateCompositorVisibility();
 
-  views::NativeWidgetMac* native_widget_mac_;  // Weak. Owns this.
+  BridgedNativeWidgetHost* const host_;       // Weak. Owns this.
+  NativeWidgetMac* const native_widget_mac_;  // Weak. Owns |host_|.
   base::scoped_nsobject<NSWindow> window_;
   base::scoped_nsobject<ViewsNSWindowDelegate> window_delegate_;
   base::scoped_nsobject<BridgedContentView> bridged_view_;
@@ -317,13 +303,16 @@
   std::unique_ptr<DragDropClientMac> drag_drop_client_;
   FocusManager* focus_manager_;  // Weak. Owned by our Widget.
   Widget::InitParams::Type widget_type_;
+  bool is_translucent_window_ = false;
 
   BridgedNativeWidgetOwner* parent_;  // Weak. If non-null, owns this.
   std::vector<BridgedNativeWidget*> child_windows_;
 
+  // The size of the most recently received compositor frame. Note that this
+  // may lag behind GetClientAreaSize.
+  gfx::Size compositor_frame_dip_size_;
   base::scoped_nsobject<NSView> compositor_superview_;
   std::unique_ptr<ui::DisplayCALayerTree> display_ca_layer_tree_;
-  std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
 
   // Tracks the bounds when the window last started entering fullscreen. Used to
   // provide an answer for GetRestoredBounds(), but not ever sent to Cocoa (it
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 98fd9ba0..fcda74e 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -23,12 +23,12 @@
 #include "ui/base/ime/input_method_factory.h"
 #include "ui/base/layout.h"
 #include "ui/base/ui_base_switches.h"
-#include "ui/compositor/recyclable_compositor_mac.h"
 #include "ui/gfx/geometry/dip_util.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #import "ui/gfx/mac/nswindow_frame_controls.h"
 #import "ui/native_theme/native_theme_mac.h"
 #import "ui/views/cocoa/bridged_content_view.h"
+#import "ui/views/cocoa/bridged_native_widget_host.h"
 #import "ui/views/cocoa/cocoa_mouse_capture.h"
 #import "ui/views/cocoa/cocoa_window_move_loop.h"
 #import "ui/views/cocoa/drag_drop_client_mac.h"
@@ -36,7 +36,6 @@
 #import "ui/views/cocoa/views_nswindow_delegate.h"
 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
 #include "ui/views/view.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/native_widget_mac.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_aura_utils.h"
@@ -222,8 +221,10 @@
   return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
 }
 
-BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
-    : native_widget_mac_(parent),
+BridgedNativeWidget::BridgedNativeWidget(BridgedNativeWidgetHost* host,
+                                         NativeWidgetMac* parent)
+    : host_(host),
+      native_widget_mac_(parent),
       focus_manager_(nullptr),
       widget_type_(Widget::InitParams::TYPE_WINDOW),  // Updated in Init().
       parent_(nullptr),
@@ -248,12 +249,13 @@
   DCHECK(child_windows_.empty());
   SetFocusManager(nullptr);
   SetRootView(nullptr);
-  DestroyCompositor();
 }
 
 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
                                const Widget::InitParams& params) {
   widget_type_ = params.type;
+  is_translucent_window_ =
+      params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
 
   DCHECK(!window_);
   window_.swap(window);
@@ -432,7 +434,7 @@
 
   // If this is ever false, the compositor will need to be properly torn down
   // and replaced, pointing at the new view.
-  DCHECK(!view || !compositor_);
+  DCHECK(!view || !compositor_superview_);
 
   drag_drop_client_.reset();
   [bridged_view_ clearView];
@@ -744,11 +746,7 @@
   // purposes of detecting a window move.
   gfx::Size new_size = GetClientAreaSize();
   native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(new_size);
-  if (layer()) {
-    UpdateLayerProperties();
-    if ([window_ inLiveResize])
-      MaybeWaitForFrame(new_size);
-  }
+  UpdateCompositorSizeAndScale();
 }
 
 void BridgedNativeWidget::OnPositionChanged() {
@@ -790,24 +788,11 @@
       [parent_->GetNSWindow() removeChildWindow:window_];
   }
 
-  // TODO(tapted): Investigate whether we want this for Mac. This is what Aura
-  // does, and it is what tests expect. However, because layer drawing is
-  // asynchronous (and things like deminiaturize in AppKit are not), it can
-  // result in the compositor producing a blank frame during the time that the
-  // layer is not visible. Avoid this by locking the compositor (preventing any
-  // new frames) in UpdateLayerVisibility whenever the layer is hidden.
-  if (layer()) {
-    UpdateLayerVisibility();
-    layer()->SchedulePaint(gfx::Rect(GetClientAreaSize()));
-
-    // For translucent windows which are made visible, recalculate shadow when
-    // the frame from the compositor arrives.
-    if (![window_ isOpaque])
-      invalidate_shadow_on_frame_swap_ = window_visible_;
-  }
-
+  // Inform the compositor of the view's size before making it visible.
+  if (window_visible_)
+    UpdateCompositorSizeAndScale();
+  UpdateCompositorVisibility();
   NotifyVisibilityChangeDown();
-
   native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
       window_visible_);
 
@@ -823,8 +808,7 @@
 }
 
 void BridgedNativeWidget::OnBackingPropertiesChanged() {
-  if (layer())
-    UpdateLayerProperties();
+  UpdateCompositorSizeAndScale();
 }
 
 void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) {
@@ -889,34 +873,16 @@
   return gfx::ScreenRectFromNSRect([window_ frame]);
 }
 
-void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
-                                      bool translucent) {
-  DCHECK(bridged_view_);
-  DCHECK(!layer());
+void BridgedNativeWidget::InitCompositorView() {
+  AddCompositorSuperview();
 
-  CreateCompositor();
-  DCHECK(compositor_);
-
-  SetLayer(std::make_unique<ui::Layer>(layer_type));
-  // Note, except for controls, this will set the layer to be hidden, since it
-  // is only called during Init().
-  UpdateLayerVisibility();
-  layer()->set_delegate(this);
-
-  InitCompositor();
-
-  // Transparent window support.
-  layer()->GetCompositor()->SetBackgroundColor(translucent ? SK_ColorTRANSPARENT
-                                                           : SK_ColorWHITE);
-  layer()->SetFillsBoundsOpaquely(!translucent);
-
-  // Use the regular window background for window modal sheets. The layer() will
+  // Use the regular window background for window modal sheets. The layer will
   // still paint over most of it, but the native -[NSApp beginSheet:] animation
   // blocks the UI thread, so there's no way to invalidate the shadow to match
   // the composited layer. This assumes the native window shape is a good match
   // for the composited NonClientFrameView, which should be the case since the
   // native shape is what's most appropriate for displaying sheets on Mac.
-  if (translucent && !native_widget_mac_->IsWindowModalSheet()) {
+  if (is_translucent_window_ && !native_widget_mac_->IsWindowModalSheet()) {
     [window_ setOpaque:NO];
     [window_ setBackgroundColor:[NSColor clearColor]];
 
@@ -930,7 +896,10 @@
     DCHECK(!ca_transaction_sync_suppressed_);
   }
 
-  UpdateLayerProperties();
+  UpdateCompositorSizeAndScale();
+  // Note, except for controls, this will set the layer to be hidden, since it
+  // is only called during initialization.
+  UpdateCompositorVisibility();
 }
 
 void BridgedNativeWidget::SetAssociationForView(const views::View* view,
@@ -1032,9 +1001,9 @@
     return false;
   if (ca_transaction_sync_suppressed_)
     return false;
-  if (!compositor_)
+  if (!compositor_superview_)
     return false;
-  return !compositor_->widget()->HasFrameOfSize(GetClientAreaSize());
+  return GetClientAreaSize() != compositor_frame_dip_size_;
 }
 
 base::TimeDelta BridgedNativeWidget::PreCommitTimeout() {
@@ -1090,34 +1059,22 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, LayerDelegate:
+// TODO(ccameron): Update class names to:
+// BridgedNativeWidgetImpl, BridgedNativeWidget:
 
-void BridgedNativeWidget::OnPaintLayer(const ui::PaintContext& context) {
-  native_widget_mac_->GetWidget()->OnNativeWidgetPaint(context);
-}
-
-void BridgedNativeWidget::OnDeviceScaleFactorChanged(
-    float old_device_scale_factor,
-    float new_device_scale_factor) {
-  native_widget_mac_->GetWidget()->DeviceScaleFactorChanged(
-      old_device_scale_factor, new_device_scale_factor);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, AcceleratedWidgetMac:
-
-void BridgedNativeWidget::AcceleratedWidgetCALayerParamsUpdated() {
+void BridgedNativeWidget::SetCALayerParams(
+    const gfx::CALayerParams& ca_layer_params) {
   // Ignore frames arriving "late" for an old size. A frame at the new size
   // should arrive soon.
-  if (!compositor_->widget()->HasFrameOfSize(GetClientAreaSize()))
+  gfx::Size frame_dip_size = gfx::ConvertSizeToDIP(ca_layer_params.scale_factor,
+                                                   ca_layer_params.pixel_size);
+  if (GetClientAreaSize() != frame_dip_size)
     return;
+  compositor_frame_dip_size_ = frame_dip_size;
 
   // Update the DisplayCALayerTree with the most recent CALayerParams, to make
   // the content display on-screen.
-  const gfx::CALayerParams* ca_layer_params =
-      compositor_->widget()->GetCALayerParams();
-  if (ca_layer_params)
-    display_ca_layer_tree_->UpdateCALayerTree(*ca_layer_params);
+  display_ca_layer_tree_->UpdateCALayerTree(ca_layer_params);
 
   if (ca_transaction_sync_suppressed_)
     ca_transaction_sync_suppressed_ = false;
@@ -1237,54 +1194,6 @@
   return gfx::Size(NSWidth(content_rect), NSHeight(content_rect));
 }
 
-void BridgedNativeWidget::CreateCompositor() {
-  DCHECK(!compositor_);
-  DCHECK(ViewsDelegate::GetInstance());
-
-  ui::ContextFactory* context_factory =
-      ViewsDelegate::GetInstance()->GetContextFactory();
-  DCHECK(context_factory);
-  ui::ContextFactoryPrivate* context_factory_private =
-      ViewsDelegate::GetInstance()->GetContextFactoryPrivate();
-
-  AddCompositorSuperview();
-
-  compositor_ = ui::RecyclableCompositorMacFactory::Get()->CreateCompositor(
-      context_factory, context_factory_private);
-  compositor_->widget()->SetNSView(this);
-}
-
-void BridgedNativeWidget::InitCompositor() {
-  TRACE_EVENT0("ui", "BridgedNativeWidget::InitCompositor");
-  DCHECK(layer());
-  float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_);
-  gfx::Size size_in_dip = GetClientAreaSize();
-  compositor_->UpdateSurface(ConvertSizeToPixel(scale_factor, size_in_dip),
-                             scale_factor);
-  compositor_->compositor()->SetRootLayer(layer());
-  compositor_->Unsuspend();
-}
-
-void BridgedNativeWidget::DestroyCompositor() {
-  if (layer()) {
-    // LayerOwner supports a change in ownership, e.g., to animate a closing
-    // window, but that won't work as expected for the root layer in
-    // BridgedNativeWidget.
-    DCHECK_EQ(this, layer()->owner());
-    layer()->CompleteAllAnimations();
-    layer()->SuppressPaint();
-    layer()->set_delegate(nullptr);
-  }
-  DestroyLayer();
-
-  if (!compositor_)
-    return;
-  compositor_->widget()->ResetNSView();
-  compositor_->compositor()->SetRootLayer(nullptr);
-  ui::RecyclableCompositorMacFactory::Get()->RecycleCompositor(
-      std::move(compositor_));
-}
-
 void BridgedNativeWidget::AddCompositorSuperview() {
   DCHECK(!compositor_superview_);
   compositor_superview_.reset(
@@ -1314,18 +1223,18 @@
   [bridged_view_ addSubview:compositor_superview_];
 }
 
-void BridgedNativeWidget::UpdateLayerProperties() {
-  DCHECK(layer());
-  DCHECK(compositor_superview_);
+void BridgedNativeWidget::UpdateCompositorSizeAndScale() {
+  // Avoid transient updates during initialization by waiting until after
+  // |compositor_superview_| is created.
+  if (!compositor_superview_)
+    return;
   float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_);
   gfx::Size size_in_dip = GetClientAreaSize();
-  gfx::Size size_in_pixel = ConvertSizeToPixel(scale_factor, size_in_dip);
 
   if (!ca_transaction_sync_suppressed_)
     ui::CATransactionCoordinator::Get().Synchronize();
 
-  layer()->SetBounds(gfx::Rect(size_in_dip));
-  compositor_->UpdateSurface(size_in_pixel, scale_factor);
+  host_->SetCompositorSize(size_in_dip, scale_factor);
 
   // For a translucent window, the shadow calculation needs to be carried out
   // after the frame from the compositor arrives.
@@ -1333,37 +1242,13 @@
     invalidate_shadow_on_frame_swap_ = true;
 }
 
-void BridgedNativeWidget::MaybeWaitForFrame(const gfx::Size& size_in_dip) {
-  return;  // TODO(https://crbug.com/682825): Delete this during cleanup.
-  if (!layer()->IsDrawn() || compositor_->widget()->HasFrameOfSize(size_in_dip))
-    return;
-
-  const int kPaintMsgTimeoutMS = 50;
-  const base::TimeTicks start_time = base::TimeTicks::Now();
-  const base::TimeTicks timeout_time =
-      start_time + base::TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
-
-  ui::WindowResizeHelperMac* resize_helper = ui::WindowResizeHelperMac::Get();
-  for (base::TimeTicks now = start_time; now < timeout_time;
-       now = base::TimeTicks::Now()) {
-    if (!resize_helper->WaitForSingleTaskToRun(timeout_time - now))
-      return;  // Timeout.
-
-    // Since the UI thread is blocked, the size shouldn't change.
-    DCHECK(size_in_dip == GetClientAreaSize());
-    if (compositor_->widget()->HasFrameOfSize(size_in_dip))
-      return;  // Frame arrived.
-  }
-}
-
 void BridgedNativeWidget::ShowAsModalSheet() {
   // -[NSApp beginSheet:] will block the UI thread while the animation runs.
   // So that it doesn't animate a fully transparent window, first wait for a
   // frame. The first step is to pretend that the window is already visible.
   window_visible_ = true;
-  UpdateLayerVisibility();
+  UpdateCompositorVisibility();
   native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(true);
-  MaybeWaitForFrame(GetClientAreaSize());
 
   NSWindow* parent_window = parent_->GetNSWindow();
   DCHECK(parent_window);
@@ -1390,12 +1275,12 @@
   return properties;
 }
 
-void BridgedNativeWidget::UpdateLayerVisibility() {
-  layer()->SetVisible(window_visible_);
-  if (window_visible_)
-    compositor_->Unsuspend();
-  else
-    compositor_->Suspend();
+void BridgedNativeWidget::UpdateCompositorVisibility() {
+  // Avoid transient updates during initialization by waiting until after
+  // |compositor_superview_| is created.
+  if (!compositor_superview_)
+    return;
+  host_->SetCompositorVisibility(window_visible_);
 }
 
 }  // namespace views
diff --git a/ui/views/cocoa/bridged_native_widget_host.h b/ui/views/cocoa/bridged_native_widget_host.h
index 084d58c..a489871b 100644
--- a/ui/views/cocoa/bridged_native_widget_host.h
+++ b/ui/views/cocoa/bridged_native_widget_host.h
@@ -14,6 +14,13 @@
 class VIEWS_EXPORT BridgedNativeWidgetHost {
  public:
   virtual ~BridgedNativeWidgetHost() = default;
+
+  // Update the ui::Compositor and ui::Layer's size.
+  virtual void SetCompositorSize(const gfx::Size& size_in_dip,
+                                 float scale_factor) = 0;
+
+  // Update the ui::Compositor and ui::Layer's visibility.
+  virtual void SetCompositorVisibility(bool visible) = 0;
 };
 
 }  // namespace views
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h
index 85777048..72c1176 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -8,8 +8,15 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
+#include "ui/compositor/layer_owner.h"
 #include "ui/views/cocoa/bridged_native_widget_host.h"
 #include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+
+namespace ui {
+class RecyclableCompositorMac;
+}
 
 namespace views {
 
@@ -20,7 +27,10 @@
 // communicates to the BridgedNativeWidget, which interacts with the Cocoa
 // APIs, and which may live in an app shim process.
 class VIEWS_EXPORT BridgedNativeWidgetHostImpl
-    : public BridgedNativeWidgetHost {
+    : public BridgedNativeWidgetHost,
+      public ui::LayerDelegate,
+      public ui::LayerOwner,
+      public ui::AcceleratedWidgetMacNSView {
  public:
   // Creates one side of the bridge. |parent| must not be NULL.
   explicit BridgedNativeWidgetHostImpl(NativeWidgetMac* parent);
@@ -31,12 +41,34 @@
   // with methods that may be sent across processes.
   BridgedNativeWidget* bridge() const { return bridge_.get(); }
 
+  // Initialize the ui::Compositor and ui::Layer.
+  void CreateCompositor(const Widget::InitParams& params);
+
  private:
+  void DestroyCompositor();
+
+  // Overridden from views::BridgedNativeWidgetHost:
+  void SetCompositorSize(const gfx::Size& size_in_dip,
+                         float scale_factor) override;
+  void SetCompositorVisibility(bool visible) override;
+
+  // Overridden from ui::LayerDelegate:
+  void OnPaintLayer(const ui::PaintContext& context) override;
+  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
+                                  float new_device_scale_factor) override;
+
+  // Overridden from ui::AcceleratedWidgetMacNSView:
+  void AcceleratedWidgetCALayerParamsUpdated() override;
+
+  views::NativeWidgetMac* const native_widget_mac_;  // Weak. Owns |this_|.
+
   // TODO(ccameron): Rather than instantiate a BridgedNativeWidget here,
   // we will instantiate a mojo BridgedNativeWidget interface to a Cocoa
   // instance that may be in another process.
   std::unique_ptr<BridgedNativeWidget> bridge_;
 
+  std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
+
   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetHostImpl);
 };
 
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 46841d8..ba1677d 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -4,14 +4,125 @@
 
 #include "ui/views/cocoa/bridged_native_widget_host_impl.h"
 
+#include "ui/compositor/recyclable_compositor_mac.h"
+#include "ui/gfx/geometry/dip_util.h"
 #include "ui/views/cocoa/bridged_native_widget.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_mac.h"
 
 namespace views {
 
 BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(
     NativeWidgetMac* parent)
-    : bridge_(new BridgedNativeWidget(parent)) {}
+    : native_widget_mac_(parent),
+      bridge_(new BridgedNativeWidget(this, parent)) {}
 
-BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {}
+BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
+  // Destroy the bridge first to prevent any calls back into this during
+  // destruction.
+  // TODO(ccameron): When all communication from |bridge_| to this goes through
+  // the BridgedNativeWidgetHost, this can be replaced with closing that pipe.
+  bridge_.reset();
+  DestroyCompositor();
+}
+
+void BridgedNativeWidgetHostImpl::CreateCompositor(
+    const Widget::InitParams& params) {
+  DCHECK(!compositor_);
+  DCHECK(!layer());
+  DCHECK(ViewsDelegate::GetInstance());
+
+  // "Infer" must be handled by ViewsDelegate::OnBeforeWidgetInit().
+  DCHECK_NE(Widget::InitParams::INFER_OPACITY, params.opacity);
+  bool translucent = params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
+
+  // Create the layer.
+  SetLayer(std::make_unique<ui::Layer>(params.layer_type));
+  layer()->set_delegate(this);
+  layer()->SetFillsBoundsOpaquely(!translucent);
+
+  // Create the compositor and attach the layer to it.
+  ui::ContextFactory* context_factory =
+      ViewsDelegate::GetInstance()->GetContextFactory();
+  DCHECK(context_factory);
+  ui::ContextFactoryPrivate* context_factory_private =
+      ViewsDelegate::GetInstance()->GetContextFactoryPrivate();
+  compositor_ = ui::RecyclableCompositorMacFactory::Get()->CreateCompositor(
+      context_factory, context_factory_private);
+  compositor_->widget()->SetNSView(this);
+  compositor_->compositor()->SetBackgroundColor(
+      translucent ? SK_ColorTRANSPARENT : SK_ColorWHITE);
+  compositor_->compositor()->SetRootLayer(layer());
+
+  // The compositor is initially locked (prevented from producing frames), and
+  // is only unlocked when the BridgedNativeWidget calls back via
+  // SetCompositorVisibility.
+  bridge_->InitCompositorView();
+}
+
+void BridgedNativeWidgetHostImpl::DestroyCompositor() {
+  if (layer()) {
+    // LayerOwner supports a change in ownership, e.g., to animate a closing
+    // window, but that won't work as expected for the root layer in
+    // BridgedNativeWidget.
+    DCHECK_EQ(this, layer()->owner());
+    layer()->CompleteAllAnimations();
+    layer()->SuppressPaint();
+    layer()->set_delegate(nullptr);
+  }
+  DestroyLayer();
+  if (!compositor_)
+    return;
+  compositor_->widget()->ResetNSView();
+  compositor_->compositor()->SetRootLayer(nullptr);
+  ui::RecyclableCompositorMacFactory::Get()->RecycleCompositor(
+      std::move(compositor_));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, views::BridgedNativeWidgetHost:
+
+void BridgedNativeWidgetHostImpl::SetCompositorSize(
+    const gfx::Size& size_in_dip,
+    float scale_factor) {
+  layer()->SetBounds(gfx::Rect(size_in_dip));
+  compositor_->UpdateSurface(ConvertSizeToPixel(scale_factor, size_in_dip),
+                             scale_factor);
+}
+
+void BridgedNativeWidgetHostImpl::SetCompositorVisibility(bool window_visible) {
+  layer()->SetVisible(window_visible);
+  if (window_visible) {
+    compositor_->Unsuspend();
+    layer()->SchedulePaint(layer()->bounds());
+  } else {
+    compositor_->Suspend();
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, LayerDelegate:
+
+void BridgedNativeWidgetHostImpl::OnPaintLayer(
+    const ui::PaintContext& context) {
+  native_widget_mac_->GetWidget()->OnNativeWidgetPaint(context);
+}
+
+void BridgedNativeWidgetHostImpl::OnDeviceScaleFactorChanged(
+    float old_device_scale_factor,
+    float new_device_scale_factor) {
+  native_widget_mac_->GetWidget()->DeviceScaleFactorChanged(
+      old_device_scale_factor, new_device_scale_factor);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, AcceleratedWidgetMac:
+
+void BridgedNativeWidgetHostImpl::AcceleratedWidgetCALayerParamsUpdated() {
+  const gfx::CALayerParams* ca_layer_params =
+      compositor_->widget()->GetCALayerParams();
+  if (ca_layer_params)
+    bridge_->SetCALayerParams(*ca_layer_params);
+}
 
 }  // namespace views
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index 76ad9a512..0f37029 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -539,7 +539,7 @@
 }
 
 void DesktopWindowTreeHostMus::SetSize(const gfx::Size& size) {
-  // Use GetBounds() as the origin of window() is always at 0, 0.
+  // Use GetBoundsInPixels(), as the origin of window() is always at (0, 0).
   gfx::Rect screen_bounds =
       gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
   screen_bounds.set_size(size);
@@ -588,11 +588,7 @@
 }
 
 gfx::Rect DesktopWindowTreeHostMus::GetWindowBoundsInScreen() const {
-  gfx::Point display_origin = GetDisplay().bounds().origin();
-  gfx::Rect bounds_in_dip =
-      gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
-  bounds_in_dip.Offset(display_origin.x(), display_origin.y());
-  return bounds_in_dip;
+  return gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
 }
 
 gfx::Rect DesktopWindowTreeHostMus::GetClientAreaBoundsInScreen() const {
@@ -622,10 +618,7 @@
 }
 
 gfx::Rect DesktopWindowTreeHostMus::GetWorkAreaBoundsInScreen() const {
-  // TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
-  return display::Screen::GetScreen()
-      ->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
-      .work_area();
+  return GetDisplay().work_area();
 }
 
 void DesktopWindowTreeHostMus::SetShape(
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index d077d45..85bfbad 100644
--- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -423,11 +423,12 @@
   Widget widget2;
   Widget::InitParams params2(Widget::InitParams::TYPE_WINDOW);
   params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params2.bounds = gfx::Rect(0, 0, 100, 100);
+  params2.bounds = gfx::Rect(800, 0, 100, 100);
   widget2.Init(params2);
-  aura::WindowTreeHostMus::ForWindow(widget2.GetNativeWindow())
-      ->set_display_id(kSecondDisplayId);
   EXPECT_EQ(gfx::Rect(800, 0, 100, 100), widget2.GetWindowBoundsInScreen());
+  EXPECT_EQ(kSecondDisplayId,
+            aura::WindowTreeHostMus::ForWindow(widget2.GetNativeWindow())
+                ->display_id());
 }
 
 // WidgetDelegate implementation that allows setting window-title and whether
diff --git a/ui/views/mus/remote_view/remote_view_provider_unittest.cc b/ui/views/mus/remote_view/remote_view_provider_unittest.cc
index f87a320..bf3a202d 100644
--- a/ui/views/mus/remote_view/remote_view_provider_unittest.cc
+++ b/ui/views/mus/remote_view/remote_view_provider_unittest.cc
@@ -14,6 +14,7 @@
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/test/mus/test_window_tree.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_tracker.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
 
@@ -159,11 +160,15 @@
   aura::Window* embedder = SimulateEmbed();
   ASSERT_TRUE(embedder);
 
+  aura::WindowTracker window_tracker;
+  window_tracker.Add(embedder);
   SimulateEmbedderClose(embedder);
+  // SimulateEmbedderClose() should delete |embedder|.
+  EXPECT_TRUE(window_tracker.windows().empty());
 
   aura::Window* new_embedder = SimulateEmbed();
+  // SimulateEmbed() should create a new window.
   ASSERT_TRUE(new_embedder);
-  EXPECT_NE(new_embedder, embedder);
 }
 
 }  // namespace views
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 3fe4565..a8bd55b 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -147,10 +147,7 @@
     bridge()->SetFocusManager(focus_manager);
   }
 
-  // "Infer" must be handled by ViewsDelegate::OnBeforeWidgetInit().
-  DCHECK_NE(Widget::InitParams::INFER_OPACITY, params.opacity);
-  bool translucent = params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
-  bridge()->CreateLayer(params.layer_type, translucent);
+  bridge_host_->CreateCompositor(params);
 }
 
 void NativeWidgetMac::OnWidgetInitDone() {
@@ -202,12 +199,13 @@
 }
 
 const ui::Compositor* NativeWidgetMac::GetCompositor() const {
-  return bridge() && bridge()->layer() ? bridge()->layer()->GetCompositor()
-                                       : nullptr;
+  return bridge_host_ && bridge_host_->layer()
+             ? bridge_host_->layer()->GetCompositor()
+             : nullptr;
 }
 
 const ui::Layer* NativeWidgetMac::GetLayer() const {
-  return bridge() ? bridge()->layer() : nullptr;
+  return bridge_host_ ? bridge_host_->layer() : nullptr;
 }
 
 void NativeWidgetMac::ReorderNativeViews() {
@@ -583,8 +581,8 @@
   target_rect.origin.y =
       NSHeight(client_rect) - target_rect.origin.y - NSHeight(target_rect);
   [GetNativeView() setNeedsDisplayInRect:target_rect];
-  if (bridge() && bridge()->layer())
-    bridge()->layer()->SchedulePaint(rect);
+  if (bridge_host_ && bridge_host_->layer())
+    bridge_host_->layer()->SchedulePaint(rect);
 }
 
 void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index b079f64..9ae776f 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -103,15 +103,11 @@
   // Simulate a frame swap from the compositor.
   void SimulateFrameSwap(const gfx::Size& size) {
     const float kScaleFactor = 1.0f;
-    ui::CALayerFrameSink* ca_layer_frame_sink =
-        ui::CALayerFrameSink::FromAcceleratedWidget(
-            bridge_->compositor_->widget()->accelerated_widget());
     gfx::CALayerParams ca_layer_params;
     ca_layer_params.is_empty = false;
     ca_layer_params.pixel_size = size;
     ca_layer_params.scale_factor = kScaleFactor;
-    ca_layer_frame_sink->UpdateCALayerTree(ca_layer_params);
-    bridge_->AcceleratedWidgetCALayerParamsUpdated();
+    bridge_->SetCALayerParams(ca_layer_params);
   }
 
   NSAnimation* show_animation() {