diff --git a/BUILD.gn b/BUILD.gn
index 62666aa..d710a40 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -162,6 +162,7 @@
       "//chrome/test:unit_tests",
       "//components:components_browsertests",
       "//components/policy:policy_templates",
+      "//components/viz:viz_unittests",
       "//components/viz/common:viz_benchmark",
       "//content/shell:content_shell",
       "//content/test:content_browsertests",
diff --git a/DEPS b/DEPS
index 8894560..bbe9928d 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,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': '8fe24272fa6d2fa9eb2458221ed9852d6ec16f56',
+  'skia_revision': '5449aade6227a1e701ebc24ee683d94a810c9a70',
   # 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': '74cef60193dd753be696e7d839ed00fa07672a35',
+  'v8_revision': 'edde5168f5bb5c07bd34192b3a58fb94ba0556d4',
   # 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.
@@ -52,7 +52,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': '27a606316e1ec4ee7cd45178de40ae1a05235f45',
+  'angle_revision': '70c95fa6ffcbe0914adb5e641288b910ddf1db12',
   # 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.
@@ -60,11 +60,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '83a6bb93fd825b975161546ff92d6fb77a7a9c22',
+  'swiftshader_revision': 'a781af7d5a1930d82d20c0cbc9d66fc8a42391e0',
   # 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': '4183f201c5155717762df48e5d68330b754070f3',
+  'pdfium_revision': '217644c0d65abfc9729c083074d505b22cd7ccf6',
   # 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.
@@ -96,7 +96,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': '72646aa580ee22cd0a37c2501a36198966d71dc5',
+  'catapult_revision': '30c9d9b855717f9d3ae27c3de6775645de74f176',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 50e9f01d..46aea901 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -54,6 +54,7 @@
         "//base/android/proguard/chromium_apk.flags",
         "//base/android/proguard/chromium_code.flags",
       ]
+      png_to_webp = true
     }
   }
 }
diff --git a/android_webview/test/embedded_test_server/java/AndroidManifest.xml b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
index aee9ecb9..ccfe776 100644
--- a/android_webview/test/embedded_test_server/java/AndroidManifest.xml
+++ b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
@@ -19,9 +19,11 @@
         <service android:name="org.chromium.android_webview.test.AwEmbeddedTestServerService"
                 android:exported="true"
                 tools:ignore="ExportedService">
-            <intent-filter android:action="org.chromium.net.test.EMBEDDED_TEST_SERVER_SERVICE" />
+            <intent-filter>
+                <action android:name="org.chromium.net.test.EMBEDDED_TEST_SERVER_SERVICE" />
+            </intent-filter>
         </service>
 
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index 4720c8a..bb3a5aa 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -50,11 +50,13 @@
            rebase_path(android_sdk_build_tools, root_build_dir) + CR
   _data += "android_sdk_build_tools_version=$android_sdk_build_tools_version$CR"
   _data +=
+      "android_sdk_tools_version_suffix=$android_sdk_tools_version_suffix$CR"
+  _data +=
       "android_sdk_root=" + rebase_path(android_sdk_root, root_build_dir) + CR
   _data += "android_sdk_version=$android_sdk_version$CR"
   _data += "android_tool_prefix=" +
            rebase_path(android_tool_prefix, root_build_dir) + CR
-  write_file("$root_build_dir/build_vars.txt", _data)
+  write_file(android_build_vars, _data)
 }
 
 # Copy to the lib.unstripped directory so that gdb can easily find it.
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index ba2311a..537a26ad 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -364,7 +364,7 @@
     res_dirs.add(
         os.path.join(self.EntryOutputDir(root_entry), _RES_SUBDIR))
     variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
-    android_manifest = root_entry.Gradle().get('android_manifest')
+    android_manifest = root_entry.DepsInfo().get('android_manifest')
     if not android_manifest:
       android_manifest = self._GenCustomManifest(root_entry)
     variables['android_manifest'] = self._Relativize(
diff --git a/build/android/gyp/merge_manifest.py b/build/android/gyp/merge_manifest.py
new file mode 100755
index 0000000..93769e19
--- /dev/null
+++ b/build/android/gyp/merge_manifest.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""Merges dependency Android manifests into a root manifest."""
+
+import argparse
+import contextlib
+import os
+import sys
+import tempfile
+import xml.dom.minidom as minidom
+
+from util import build_utils
+
+# Tools library directory - relative to Android SDK root
+SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib')
+
+MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger'
+MANIFEST_MERGER_JARS = [
+  'common{suffix}.jar',
+  'manifest-merger{suffix}.jar',
+  'sdk-common{suffix}.jar',
+  'sdklib{suffix}.jar',
+]
+
+TOOLS_NAMESPACE_PREFIX = 'tools'
+TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
+
+
+@contextlib.contextmanager
+def _PatchedManifest(manifest_path):
+  """Patches an Android manifest to always include the 'tools' namespace
+  declaration, as it is not propagated by the manifest merger from the SDK.
+
+  See https://issuetracker.google.com/issues/63411481
+  """
+  doc = minidom.parse(manifest_path)
+  manifests = doc.getElementsByTagName('manifest')
+  assert len(manifests) == 1
+  manifest = manifests[0]
+
+  manifest.setAttribute('xmlns:%s' % TOOLS_NAMESPACE_PREFIX, TOOLS_NAMESPACE)
+
+  tmp_prefix = os.path.basename(manifest_path)
+  with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest:
+    doc.writexml(patched_manifest)
+    patched_manifest.flush()
+    yield patched_manifest.name
+
+
+def _BuildManifestMergerClasspath(build_vars):
+  return ':'.join([
+    os.path.join(
+      build_vars['android_sdk_root'],
+      SDK_TOOLS_LIB_DIR,
+      jar.format(suffix=build_vars['android_sdk_tools_version_suffix']))
+    for jar in MANIFEST_MERGER_JARS
+  ])
+
+
+def main(argv):
+  argv = build_utils.ExpandFileArgs(argv)
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--build-vars',
+                      help='Path to GN build vars file',
+                      required=True)
+  parser.add_argument('--root-manifest',
+                      help='Root manifest which to merge into',
+                      required=True)
+  parser.add_argument('--output', help='Output manifest path', required=True)
+  parser.add_argument('--extras',
+                      help='GN list of additional manifest to merge')
+  args = parser.parse_args(argv)
+
+  cmd = [
+    'java',
+    '-cp',
+    _BuildManifestMergerClasspath(build_utils.ReadBuildVars(args.build_vars)),
+    MANIFEST_MERGER_MAIN_CLASS,
+    '--out', args.output,
+  ]
+
+  extras = build_utils.ParseGnList(args.extras)
+  if extras:
+    cmd += ['--libs', ':'.join(extras)]
+
+  with _PatchedManifest(args.root_manifest) as root_manifest:
+    cmd += ['--main', root_manifest]
+    build_utils.CheckOutput(cmd,
+      # https://issuetracker.google.com/issues/63514300: The merger doesn't set
+      # a nonzero exit code for failures.
+      fail_func=lambda returncode, stderr: returncode != 0 or
+        build_utils.IsTimeStale(args.output, [root_manifest] + extras))
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 7b2f48dd..422bfee3 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -21,6 +21,7 @@
 import md5_check  # pylint: disable=relative-import
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+from pylib import constants
 from pylib.constants import host_paths
 
 sys.path.append(os.path.join(os.path.dirname(__file__),
@@ -81,6 +82,14 @@
   return all_files
 
 
+def ReadBuildVars(build_vars_path=None):
+  if not build_vars_path:
+    build_vars_path = os.path.join(constants.GetOutDirectory(),
+                                   "build_vars.txt")
+  with open(build_vars_path) as f:
+    return dict(l.rstrip().split('=', 1) for l in f)
+
+
 def ParseGnList(gn_string):
   """Converts a command-line parameter into a list.
 
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 6eab4b2..c2dee9a 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -410,7 +410,8 @@
     deps_info['gradle_treat_as_prebuilt'] = options.gradle_treat_as_prebuilt
 
   if options.android_manifest:
-    gradle['android_manifest'] = options.android_manifest
+    deps_info['android_manifest'] = options.android_manifest
+
   if options.type in ('java_binary', 'java_library', 'android_apk'):
     if options.java_sources_file:
       deps_info['java_sources_file'] = options.java_sources_file
@@ -706,6 +707,9 @@
     config['uncompressed_locales_java_list'] = (
         _CreateLocalePaksAssetJavaList(config['uncompressed_assets']))
 
+    config['extra_android_manifests'] = filter(None, (
+        d.get('android_manifest') for d in all_resources_deps))
+
     # Collect java resources
     java_resources_jars = [d['java_resources_jar'] for d in all_library_deps
                           if 'java_resources_jar' in d]
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index c93f675..76f03fb 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -771,11 +771,6 @@
                     'Your output directory is likely stale.')
 
 
-def _ReadBuildVars(output_dir):
-  with open(os.path.join(output_dir, 'build_vars.txt')) as f:
-    return dict(l.replace('//', '').rstrip().split('=', 1) for l in f)
-
-
 def main():
   argparser = argparse.ArgumentParser(description='Print APK size metrics.')
   argparser.add_argument('--min-pak-resource-size', type=int, default=20*1024,
@@ -814,7 +809,7 @@
   if not args.no_output_dir:
     constants.CheckOutputDirectory()
     devil_chromium.Initialize()
-    build_vars = _ReadBuildVars(constants.GetOutDirectory())
+    build_vars = build_utils.ReadBuildVars()
     tools_prefix = os.path.join(constants.GetOutDirectory(),
                                 build_vars['android_tool_prefix'])
   else:
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 141d3941..b47c723c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -45,6 +45,7 @@
     default_android_sdk_root = "//third_party/android_tools/sdk"
     default_android_sdk_version = "26"
     default_android_sdk_build_tools_version = "26.0.0"
+    default_android_sdk_tools_version_suffix = "-25.3.2"
   }
 
   if (!defined(default_lint_android_sdk_root)) {
@@ -104,6 +105,7 @@
     android_sdk_root = default_android_sdk_root
     android_sdk_version = default_android_sdk_version
     android_sdk_build_tools_version = default_android_sdk_build_tools_version
+    android_sdk_tools_version_suffix = default_android_sdk_tools_version_suffix
 
     lint_android_sdk_root = default_lint_android_sdk_root
     lint_android_sdk_version = default_lint_android_sdk_version
@@ -194,6 +196,9 @@
   assert(!(enable_incremental_dx && !is_java_debug))
   assert(!(enable_incremental_javac && !is_java_debug))
 
+  # Path to where selected build variables are written to.
+  android_build_vars = "$root_build_dir/build_vars.txt"
+
   # Host stuff -----------------------------------------------------------------
 
   # Defines the name the Android build gives to the current host CPU
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 7ae86ac..e7a2c5b 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1777,11 +1777,11 @@
       }
       sources = []
     }
-    _android_manifest_deps = []
+    _android_root_manifest_deps = []
     if (defined(invoker.android_manifest_dep)) {
-      _android_manifest_deps = [ invoker.android_manifest_dep ]
+      _android_root_manifest_deps = [ invoker.android_manifest_dep ]
     }
-    _android_manifest = invoker.android_manifest
+    _android_root_manifest = invoker.android_manifest
 
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
     _create_abi_split =
@@ -1820,13 +1820,13 @@
       incremental_install_script_path = _incremental_install_script_path
       resources_zip = resources_zip_path
       build_config = _build_config
-      android_manifest = _android_manifest
+      android_manifest = _android_root_manifest
 
       if (defined(_java_sources_file)) {
         java_sources_file = _java_sources_file
       }
 
-      deps = _android_manifest_deps
+      deps = _android_root_manifest_deps
 
       if (defined(invoker.deps)) {
         possible_config_deps = invoker.deps
@@ -1856,6 +1856,34 @@
       }
     }
 
+    _android_manifest =
+        "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml"
+    android_manifest_target = "${_template_name}__merge_manifests"
+    action(android_manifest_target) {
+      script = "//build/android/gyp/merge_manifest.py"
+
+      sources = [
+        _android_root_manifest,
+      ]
+
+      outputs = [
+        _android_manifest,
+      ]
+
+      args = [
+        "--build-vars",
+        rebase_path(android_build_vars, root_build_dir),
+        "--root-manifest",
+        rebase_path(_android_root_manifest, root_build_dir),
+        "--output",
+        rebase_path(_android_manifest, root_build_dir),
+        "--extras",
+        "@FileArg($_rebased_build_config:extra_android_manifests)",
+      ]
+
+      deps = _android_root_manifest_deps + [ ":$build_config_target" ]
+    }
+
     _final_deps = []
 
     if (enable_multidex) {
@@ -1886,7 +1914,10 @@
       }
 
       build_config = _build_config
-      deps = _android_manifest_deps + [ ":$build_config_target" ]
+      deps = [
+        ":$android_manifest_target",
+        ":$build_config_target",
+      ]
       if (defined(invoker.deps)) {
         deps += invoker.deps
       }
@@ -1992,7 +2023,10 @@
       supports_android = true
       requires_android = true
       override_build_config = _build_config
-      deps = _android_manifest_deps + [ ":$build_config_target" ]
+      deps = [
+        ":$android_manifest_target",
+        ":$build_config_target",
+      ]
 
       android_manifest = _android_manifest
       srcjar_deps = _srcjar_deps
@@ -2268,17 +2302,19 @@
       keystore_password = _keystore_password
 
       # Incremental apk does not use native libs nor final dex.
-      incremental_deps = deps + _android_manifest_deps + [
+      incremental_deps = deps + [
+                           ":$android_manifest_target",
                            ":$build_config_target",
                            ":$process_resources_target",
                          ]
 
       # This target generates the input file _all_resources_zip_path.
-      deps += _android_manifest_deps + [
-                ":$build_config_target",
-                ":$process_resources_target",
-                ":$final_dex_target_name",
-              ]
+      deps += [
+        ":$android_manifest_target",
+        ":$build_config_target",
+        ":$final_dex_target_name",
+        ":$process_resources_target",
+      ]
 
       if ((_native_libs_deps != [] ||
            _extra_native_libs_even_when_incremental != []) &&
@@ -2311,7 +2347,9 @@
         out_manifest =
             "$gen_dir/split-manifests/${android_app_abi}/AndroidManifest.xml"
         split_name = "abi_${android_app_abi}"
-        deps = _android_manifest_deps
+        deps = [
+          ":$android_manifest_target",
+        ]
       }
 
       _apk_rule = "${_template_name}__split_apk_abi_${android_app_abi}"
diff --git a/chrome/OWNERS b/chrome/OWNERS
index e0132b8..fbf4726 100644
--- a/chrome/OWNERS
+++ b/chrome/OWNERS
@@ -12,3 +12,5 @@
 # structural changes, please get a review from a reviewer in this file.
 per-file *.gni=*
 per-file BUILD.gn=file://build/OWNERS
+per-file VERSION=dimu@chromium.com
+per-file VERSION=mmoss@chromium.com
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c59688c1..73b2877 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -861,6 +861,10 @@
   apk_name = "ChromeModernPublic"
   shared_libraries = [ ":chrome" ]
 
+  if (!is_java_debug) {
+    png_to_webp = true
+  }
+
   # Always enable load_library_from_apk.
   load_library_from_apk = chromium_linker_supported
 }
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 9f8ad322..037d16b3 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -143,6 +143,7 @@
         proguard_configs = []
       }
       proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
+      png_to_webp = true
     }
   }
 }
diff --git a/chrome/android/java/res/layout/password_entry_editor_interactive.xml b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
index 014fe390..f758811 100644
--- a/chrome/android/java/res/layout/password_entry_editor_interactive.xml
+++ b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
@@ -15,48 +15,7 @@
         android:orientation="vertical"
         android:title="@string/password_entry_editor_title">
 
-        <TextView
-            android:text="@string/password_entry_editor_site_title"
-            android:textColor="@color/google_blue_700"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="10dp"
-            android:layout_marginStart="15dp"
-            android:gravity="center_vertical"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-
-            <TextView
-                android:id="@+id/password_entry_editor_url"
-                android:textColor="@color/default_text_color"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="10dp"
-                android:layout_marginStart="15dp"
-                android:textAppearance="?android:attr/textAppearanceMedium" />
-
-            <View
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <ImageButton
-                android:id="@+id/password_entry_editor_copy_site"
-                android:background="@null"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="end"
-                android:layout_marginTop="10dp"
-                android:layout_marginEnd="15dp"
-                android:src="@drawable/ic_content_copy"
-                android:contentDescription="@string/password_entry_editor_copy_stored_site"
-                style="?android:attr/buttonStyleSmall" />
-
-        </LinearLayout>
+        <include layout="@layout/password_entry_editor_site_row"/>
 
         <TextView
             android:text="@string/password_entry_editor_username_title"
diff --git a/chrome/android/java/res/layout/password_entry_editor_site_row.xml b/chrome/android/java/res/layout/password_entry_editor_site_row.xml
new file mode 100644
index 0000000..cd5a77fd
--- /dev/null
+++ b/chrome/android/java/res/layout/password_entry_editor_site_row.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. -->
+
+<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:orientation="vertical">
+
+    <TextView
+        android:text="@string/password_entry_editor_site_title"
+        android:textColor="@color/google_blue_700"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:layout_marginStart="15dp"
+        android:gravity="center_vertical"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/password_entry_editor_url"
+            android:textColor="@color/default_text_color"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:layout_marginStart="15dp"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <View
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <ImageButton
+            android:id="@+id/password_entry_editor_copy_site"
+            android:background="@null"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:layout_marginTop="10dp"
+            android:layout_marginEnd="15dp"
+            android:src="@drawable/ic_content_copy"
+            android:contentDescription="@string/password_entry_editor_copy_stored_site"
+            style="?android:attr/buttonStyleSmall" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/chrome/android/java/res/layout/password_entry_exception.xml b/chrome/android/java/res/layout/password_entry_exception.xml
new file mode 100644
index 0000000..f71bcdf0
--- /dev/null
+++ b/chrome/android/java/res/layout/password_entry_exception.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true" >
+
+    <LinearLayout
+        android:id="@+id/password_entry_exception"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:title="@string/password_entry_editor_title">
+
+        <include layout="@layout/password_entry_editor_site_row"/>
+    </LinearLayout>
+
+</ScrollView>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 3addc59..88e60cc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -154,6 +154,7 @@
     public static final String CCT_BACKGROUND_TAB = "CCTBackgroundTab";
     public static final String CCT_EXTERNAL_LINK_HANDLING = "CCTExternalLinkHandling";
     public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI";
+    public static final String CCT_REDIRECT_PRECONNECT = "CCTRedirectPreconnect";
     public static final String CHROME_HOME = "ChromeHome";
     public static final String CHROME_HOME_EXPAND_BUTTON = "ChromeHomeExpandButton";
     public static final String CONSISTENT_OMNIBOX_GEOLOCATION = "ConsistentOmniboxGeolocation";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index 7c6ccb38..5dbfe443 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -6,6 +6,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -227,24 +228,29 @@
      */
     public void maybePreconnectUrlAndSubResources(Profile profile, String url) {
         ThreadUtils.assertOnUiThread();
-        if (!DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()) {
-            // If there is already a DNS request in flight for this URL, then
-            // the preconnection will start by issuing a DNS request for the
-            // same domain, as the result is not cached. However, such a DNS
-            // request has already been sent from this class, so it is better to
-            // wait for the answer to come back before preconnecting. Otherwise,
-            // the preconnection logic will wait for the result of the second
-            // DNS request, which should arrive after the result of the first
-            // one. Note that we however need to wait for the main thread to be
-            // available in this case, since the preconnection will be sent from
-            // AsyncTask.onPostExecute(), which may delay it.
-            if (mDnsRequestsInFlight.contains(url)) {
-                // Note that if two requests come for the same URL with two
-                // different profiles, the last one will win.
-                mPendingPreconnectWithProfile.put(url, profile);
-            } else {
-                nativePreconnectUrlAndSubresources(profile, url);
-            }
+
+        Uri uri = Uri.parse(url);
+        if (uri == null) return;
+        // HTTP connections will not be used when the data reduction proxy is enabled.
+        if (DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()
+                && UrlConstants.HTTP_SCHEME.equals(uri.normalizeScheme().getScheme())) {
+            return;
+        }
+
+        // If there is already a DNS request in flight for this URL, then the preconnection will
+        // start by issuing a DNS request for the same domain, as the result is not cached. However,
+        // such a DNS request has already been sent from this class, so it is better to wait for the
+        // answer to come back before preconnecting. Otherwise, the preconnection logic will wait
+        // for the result of the second DNS request, which should arrive after the result of the
+        // first one. Note that we however need to wait for the main thread to be available in this
+        // case, since the preconnection will be sent from AsyncTask.onPostExecute(), which may
+        // delay it.
+        if (mDnsRequestsInFlight.contains(url)) {
+            // Note that if two requests come for the same URL with two different profiles, the last
+            // one will win.
+            mPendingPreconnectWithProfile.put(url, profile);
+        } else {
+            nativePreconnectUrlAndSubresources(profile, url);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 8b47612..47b25c28 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -13,6 +13,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
 import android.support.annotation.IdRes;
 import android.support.annotation.Nullable;
 import android.view.Gravity;
@@ -26,6 +27,7 @@
 import android.view.View.OnKeyListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
+import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ImageButton;
@@ -163,6 +165,11 @@
         mPopup.setFocusable(true);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
 
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            // The window layout type affects the z-index of the popup window on M+.
+            mPopup.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+        }
+
         boolean anchorAtBottom = isAnchorAtBottom(anchorView, visibleDisplayFrame);
         int footerHeight = 0;
         mPopup.setOnDismissListener(new OnDismissListener() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
index 1487e1f..d5038af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -493,6 +493,20 @@
                               : params.mSpeculationMode;
     }
 
+    /**
+     * Returns whether an origin is first-party with respect to a session, that is if the
+     * application linked to the session has a relation with the provided origin. This does not
+     * calls OriginVerifier, but only checks the cached relations.
+     *
+     * @param session The session.
+     * @param origin Origin to verify
+     */
+    public synchronized boolean isFirstPartyOriginForSession(
+            CustomTabsSessionToken session, Uri origin) {
+        SessionParams params = mSessionParams.get(session);
+        return params == null ? false : OriginVerifier.isValidOrigin(params.packageName, origin);
+    }
+
     /** Tries to bind to a client to keep it alive, and returns true for success. */
     public synchronized boolean keepAliveForSession(CustomTabsSessionToken session, Intent intent) {
         // When an application is bound to a service, its priority is raised to
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 7d83ded..23e12bf 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
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.customtabs;
 
 import android.app.Activity;
+import android.app.Application;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -237,6 +238,9 @@
 
         String url = IntentHandler.getUrlFromIntent(intent);
         if (TextUtils.isEmpty(url)) return false;
+        CustomTabsConnection connection = CustomTabsConnection.getInstance(
+                (Application) ContextUtils.getApplicationContext());
+        connection.onHandledIntent(session, url, intent);
         sActiveContentHandler.loadUrlAndTrackFromTimestamp(new LoadUrlParams(url),
                 IntentHandler.getTimestampFromIntent(intent));
         return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 8ca1690..e79e1d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -28,6 +28,7 @@
 import android.widget.RemoteViews;
 
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TimeUtils;
@@ -56,6 +57,7 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.Referrer;
+import org.chromium.net.GURLUtils;
 
 import java.io.BufferedReader;
 import java.io.FileReader;
@@ -116,6 +118,10 @@
     @VisibleForTesting
     static final int HIDDEN_TAB = 3;
 
+    // TODO(lizeb): Move to the support library.
+    @VisibleForTesting
+    static final String REDIRECT_ENDPOINT_KEY = "android.support.customtabs.REDIRECT_ENDPOINT";
+
     private static AtomicReference<CustomTabsConnection> sInstance = new AtomicReference<>();
 
     /** Holds the parameters for the current speculation. */
@@ -346,15 +352,15 @@
         return true;
     }
 
-    /** @return the URL converted to string, or null if it's invalid. */
-    private static String checkAndConvertUri(Uri uri) {
-        if (uri == null) return null;
+    /** @return the URL or null if it's invalid. */
+    private boolean isValid(Uri uri) {
+        if (uri == null) return false;
         // Don't do anything for unknown schemes. Not having a scheme is allowed, as we allow
         // "www.example.com".
         String scheme = uri.normalizeScheme().getScheme();
         boolean allowedScheme = scheme == null || scheme.equals("http") || scheme.equals("https");
-        if (!allowedScheme) return null;
-        return uri.toString();
+        if (!allowedScheme) return false;
+        return true;
     }
 
     /**
@@ -397,7 +403,7 @@
         boolean atLeastOneUrl = false;
         if (likelyBundles == null) return false;
         WarmupManager warmupManager = WarmupManager.getInstance();
-        Profile profile = Profile.getLastUsedProfile();
+        Profile profile = Profile.getLastUsedProfile().getOriginalProfile();
         for (Bundle bundle : likelyBundles) {
             Uri uri;
             try {
@@ -405,9 +411,8 @@
             } catch (ClassCastException e) {
                 continue;
             }
-            String url = checkAndConvertUri(uri);
-            if (url != null) {
-                warmupManager.maybePreconnectUrlAndSubResources(profile, url);
+            if (isValid(uri)) {
+                warmupManager.maybePreconnectUrlAndSubResources(profile, uri.toString());
                 atLeastOneUrl = true;
             }
         }
@@ -430,7 +435,7 @@
             final Bundle extras, final List<Bundle> otherLikelyBundles) {
         final boolean lowConfidence =
                 (url == null || TextUtils.isEmpty(url.toString())) && otherLikelyBundles != null;
-        final String urlString = checkAndConvertUri(url);
+        final String urlString = isValid(url) ? url.toString() : null;
         if (url != null && urlString == null && !lowConfidence) return false;
 
         // Things below need the browser process to be initialized.
@@ -725,6 +730,35 @@
         return null;
     }
 
+    /**
+     * Called when an intent is handled by either an existing or a new CustomTabActivity.
+     *
+     * @param session Session extracted from the intent.
+     * @param url URL extracted from the intent.
+     * @param intent incoming intent.
+     */
+    void onHandledIntent(CustomTabsSessionToken session, String url, Intent intent) {
+        // For the preconnection to not be a no-op, we need more than just the native library.
+        Context context = ContextUtils.getApplicationContext();
+        if (!ChromeBrowserInitializer.getInstance(context).hasNativeInitializationCompleted()) {
+            return;
+        }
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_REDIRECT_PRECONNECT)) return;
+
+        // Conditions:
+        // - There is a valid redirect endpoint.
+        // - The URL's origin is first party with respect to the app.
+        Uri redirectEndpoint = intent.getParcelableExtra(REDIRECT_ENDPOINT_KEY);
+        if (redirectEndpoint == null || !isValid(redirectEndpoint)) return;
+
+        String origin = GURLUtils.getOrigin(url);
+        if (origin == null) return;
+        if (!mClientManager.isFirstPartyOriginForSession(session, Uri.parse(origin))) return;
+
+        WarmupManager.getInstance().maybePreconnectUrlAndSubResources(
+                Profile.getLastUsedProfile(), redirectEndpoint.toString());
+    }
+
     /** See {@link ClientManager#getReferrerForSession(CustomTabsSessionToken)} */
     public Referrer getReferrerForSession(CustomTabsSessionToken session) {
         return mClientManager.getReferrerForSession(session);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
index b7c6ba4..9754d33 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
@@ -30,8 +30,10 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Used to verify postMessage origin for a designated package name.
@@ -47,21 +49,25 @@
 class OriginVerifier {
     private static final String TAG = "OriginVerifier";
     private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray();
-    private static Map<String, Uri> sCachedOriginMap;
+    private static Map<String, Set<Uri>> sPackageToCachedOrigins;
     private final OriginVerificationListener mListener;
     private final String mPackageName;
     private final String mSignatureFingerprint;
     private long mNativeOriginVerifier = 0;
     private Uri mOrigin;
 
-    /**
-     * To be used for prepopulating verified origin for testing functionality.
-     * @param packageName The package name to prepopulate for.
-     * @param origin The origin to add as verified.
-     */
-    @VisibleForTesting
-    static void prePopulateVerifiedOriginForTesting(String packageName, Uri origin) {
-        cacheVerifiedOriginIfNeeded(packageName, origin);
+    /** Small helper class to post a result of origin verification. */
+    private class VerifiedCallback implements Runnable {
+        private final boolean mResult;
+
+        public VerifiedCallback(boolean result) {
+            this.mResult = result;
+        }
+
+        @Override
+        public void run() {
+            originVerified(mResult);
+        }
     }
 
     private static Uri getPostMessageOriginFromVerifiedOrigin(
@@ -70,11 +76,44 @@
                 + verifiedOrigin.getHost() + "/" + packageName);
     }
 
-    private static void cacheVerifiedOriginIfNeeded(String packageName, Uri origin) {
-        if (sCachedOriginMap == null) sCachedOriginMap = new HashMap<>();
-        if (!sCachedOriginMap.containsKey(packageName)) {
-            sCachedOriginMap.put(packageName, origin);
+    /** Clears all known relations. */
+    @VisibleForTesting
+    static void reset() {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins != null) sPackageToCachedOrigins.clear();
+    }
+
+    /**
+     * Mark an origin as verified for a package.
+     * @param packageName The package name to prepopulate for.
+     * @param origin The origin to add as verified.
+     */
+    static void addVerifiedOriginForPackage(String packageName, Uri origin) {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins == null) sPackageToCachedOrigins = new HashMap<>();
+        Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName);
+        if (cachedOrigins == null) {
+            cachedOrigins = new HashSet<Uri>();
+            sPackageToCachedOrigins.put(packageName, cachedOrigins);
         }
+        cachedOrigins.add(origin);
+    }
+
+    /**
+     * Returns whether an origin is first-party relative to a given package name.
+     *
+     * This only returns data from previously cached relations, and does not
+     * trigger an asynchronous validation.
+     *
+     * @param packageName The package name
+     * @param origin The origin to verify
+     */
+    static boolean isValidOrigin(String packageName, Uri origin) {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins == null) return false;
+        Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName);
+        if (cachedOrigins == null) return false;
+        return cachedOrigins.contains(origin);
     }
 
     /**
@@ -112,24 +151,13 @@
         ThreadUtils.assertOnUiThread();
         mOrigin = origin;
         if (!UrlConstants.HTTPS_SCHEME.equals(mOrigin.getScheme().toLowerCase(Locale.US))) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(false);
-                }
-            });
+            ThreadUtils.runOnUiThread(new VerifiedCallback(false));
             return;
         }
 
         // If this origin is cached as verified already, use that.
-        Uri cachedOrigin = getCachedOriginIfExists();
-        if (cachedOrigin != null && cachedOrigin.equals(origin)) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(true);
-                }
-            });
+        if (isValidOrigin(mPackageName, origin)) {
+            ThreadUtils.runOnUiThread(new VerifiedCallback(true));
             return;
         }
         if (mNativeOriginVerifier != 0) cleanUp();
@@ -142,14 +170,7 @@
         assert mNativeOriginVerifier != 0;
         boolean success = nativeVerifyOrigin(
                 mNativeOriginVerifier, mPackageName, mSignatureFingerprint, mOrigin.toString());
-        if (!success) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(false);
-                }
-            });
-        }
+        if (!success) ThreadUtils.runOnUiThread(new VerifiedCallback(false));
     }
 
     /**
@@ -219,18 +240,13 @@
     @CalledByNative
     private void originVerified(boolean originVerified) {
         if (originVerified) {
-            cacheVerifiedOriginIfNeeded(mPackageName, mOrigin);
+            addVerifiedOriginForPackage(mPackageName, mOrigin);
             mOrigin = getPostMessageOriginFromVerifiedOrigin(mPackageName, mOrigin);
         }
         mListener.onOriginVerified(mPackageName, mOrigin, originVerified);
         cleanUp();
     }
 
-    private Uri getCachedOriginIfExists() {
-        if (sCachedOriginMap == null) return null;
-        return sCachedOriginMap.get(mPackageName);
-    }
-
     private native long nativeInit(Profile profile);
     private native boolean nativeVerifyOrigin(long nativeOriginVerifier, String packageName,
             String signatureFingerprint, String origin);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 3238705..dbb3204 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -113,6 +113,13 @@
     }
 
     /**
+     * @return whether native initialization is complete.
+     */
+    public boolean hasNativeInitializationCompleted() {
+        return mNativeInitializationComplete;
+    }
+
+    /**
      * Initializes the Chrome browser process synchronously.
      *
      * @throws ProcessInitException if there is a problem with the native library.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 2cc2d10..4f61348 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -280,11 +280,13 @@
 
         mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * getMaxTileColumns());
 
+        mRecyclerView.init(mUiConfig, mContextMenuManager);
+
         // Set up snippets
         NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout,
                 mUiConfig, offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null);
         newTabPageAdapter.refreshSuggestions();
-        mRecyclerView.init(mUiConfig, mContextMenuManager, newTabPageAdapter);
+        mRecyclerView.setAdapter(newTabPageAdapter);
         mRecyclerView.getLinearLayoutManager().scrollToPosition(scrollPosition);
 
         setupScrollHandling();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 0eab84b..1bc12d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -256,7 +256,7 @@
 
         // We are assuming for now that the adapter is used with a single RecyclerView.
         // Getting the reference as we are doing here is going to be broken if that changes.
-        assert mRecyclerView == null;
+        assert mRecyclerView == null || recyclerView == mRecyclerView;
 
         // FindBugs chokes on the cast below when not checked, raising BC_UNCONFIRMED_CAST
         assert recyclerView instanceof SuggestionsRecyclerView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index cdf82a9218..f7d3275 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -66,14 +66,6 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (shouldDisplayInteractivePasswordEntryEditor()) {
-            mView = inflater.inflate(R.layout.password_entry_editor_interactive, container, false);
-        } else {
-            mView = inflater.inflate(R.layout.password_entry_editor, container, false);
-        }
-        getActivity().setTitle(R.string.password_entry_editor_title);
-        mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService(
-                Context.CLIPBOARD_SERVICE);
         // Extras are set on this intent in class {@link SavePasswordsPreferences}.
         mExtras = getArguments();
         assert mExtras != null;
@@ -81,12 +73,28 @@
         final String name = mExtras.containsKey(SavePasswordsPreferences.PASSWORD_LIST_NAME)
                 ? mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_NAME)
                 : null;
+
+        mException = (name == null);
+        if (shouldDisplayInteractivePasswordEntryEditor()) {
+            if (!mException) {
+                mView = inflater.inflate(
+                        R.layout.password_entry_editor_interactive, container, false);
+            } else {
+                mView = inflater.inflate(R.layout.password_entry_exception, container, false);
+            }
+        } else {
+            mView = inflater.inflate(R.layout.password_entry_editor, container, false);
+        }
+        getActivity().setTitle(R.string.password_entry_editor_title);
+        mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService(
+                Context.CLIPBOARD_SERVICE);
         TextView nameView = (TextView) mView.findViewById(R.id.password_entry_editor_name);
-        if (name != null) {
+        if (!mException) {
             nameView.setText(name);
         } else {
-            nameView.setText(R.string.section_saved_passwords_exceptions);
-            mException = true;
+            if (!shouldDisplayInteractivePasswordEntryEditor()) {
+                nameView.setText(R.string.section_saved_passwords_exceptions);
+            }
         }
         final String url = mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_URL);
         TextView urlView = (TextView) mView.findViewById(R.id.password_entry_editor_url);
@@ -95,9 +103,11 @@
             mKeyguardManager =
                     (KeyguardManager) getActivity().getApplicationContext().getSystemService(
                             Context.KEYGUARD_SERVICE);
-            hidePassword();
-            hookupPasswordButtons();
-            hookupCopyUsernameButton();
+            if (!mException) {
+                hidePassword();
+                hookupPasswordButtons();
+                hookupCopyUsernameButton();
+            }
             hookupCopySiteButton();
         } else {
             hookupCancelDeleteButtons();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index b53bb9f..7f43a36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -80,15 +80,17 @@
         });
 
         UiConfig uiConfig = new UiConfig(mRecyclerView);
+        mRecyclerView.init(uiConfig, mContextMenuManager);
 
         final NewTabPageAdapter adapter = new NewTabPageAdapter(mSuggestionsUiDelegate,
                 /* aboveTheFoldView = */ null, uiConfig, OfflinePageBridge.getForProfile(profile),
                 mContextMenuManager, mTileGroupDelegate);
-        mRecyclerView.init(uiConfig, mContextMenuManager, adapter);
 
         mBottomSheetObserver = new SuggestionsSheetVisibilityChangeObserver(this, activity) {
             @Override
             public void onSheetOpened() {
+                mRecyclerView.setAdapter(adapter);
+
                 mRecyclerView.scrollToPosition(0);
                 adapter.refreshSuggestions();
                 mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened();
@@ -121,6 +123,12 @@
                     SuggestionsMetrics.recordSurfaceFullyVisible();
                 }
             }
+
+            @Override
+            public void onSheetClosed() {
+                super.onSheetClosed();
+                mRecyclerView.setAdapter(null);
+            }
         };
 
         mShadowView = (FadingShadowView) mView.findViewById(R.id.shadow);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
index 3411205..13f6e192 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
@@ -192,11 +192,9 @@
         super.onLayout(changed, l, t, r, b);
     }
 
-    public void init(
-            UiConfig uiConfig, ContextMenuManager contextMenuManager, NewTabPageAdapter adapter) {
+    public void init(UiConfig uiConfig, ContextMenuManager contextMenuManager) {
         mUiConfig = uiConfig;
         mContextMenuManager = contextMenuManager;
-        setAdapter(adapter);
     }
 
     public NewTabPageAdapter getNewTabPageAdapter() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 54ebfe9..b6fe6ce7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -159,12 +159,6 @@
     /** Whether the disappearance of the toolbar buttons is currently animating. */
     private boolean mAnimatingToolbarButtonDisappearance;
 
-    /** The current left position of the location bar background. */
-    private int mLocationBarBackgroundLeftPosition;
-
-    /** The current right position of the location bar background. */
-    private int mLocationBarBackgroundRightPosition;
-
     /**
      * Constructs a BottomToolbarPhone object.
      * @param context The Context in which this View object is created.
@@ -356,31 +350,25 @@
     @Override
     protected int getLeftPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
-            mLocationBarBackgroundLeftPosition =
-                    super.getLeftPositionOfLocationBarBackground(visualState);
+            return super.getLeftPositionOfLocationBarBackground(visualState);
         } else {
             int targetPosition = getViewBoundsLeftOfLocationBar(visualState);
             int currentPosition = targetPosition + getLocationBarBackgroundLeftOffset();
-            mLocationBarBackgroundLeftPosition = (int) MathUtils.interpolate(
+            return (int) MathUtils.interpolate(
                     targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
-
-        return mLocationBarBackgroundLeftPosition;
     }
 
     @Override
     protected int getRightPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
-            mLocationBarBackgroundRightPosition =
-                    super.getRightPositionOfLocationBarBackground(visualState);
+            return super.getRightPositionOfLocationBarBackground(visualState);
         } else {
             int targetPosition = getViewBoundsRightOfLocationBar(visualState);
             int currentPosition = targetPosition - getLocationBarBackgroundRightOffset();
-            mLocationBarBackgroundRightPosition = (int) MathUtils.interpolate(
+            return (int) MathUtils.interpolate(
                     targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
-
-        return mLocationBarBackgroundRightPosition;
     }
 
     private int getLocationBarBackgroundLeftOffset() {
@@ -733,18 +721,28 @@
 
         float locationBarTranslationX;
         boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mLocationBar);
-
-        if (isLocationBarRtl) {
-            locationBarTranslationX = mLocationBarBackgroundRightPosition
-                    - mUnfocusedLocationBarLayoutWidth - mUnfocusedLocationBarLayoutLeft;
-        } else {
-            locationBarTranslationX =
-                    mUnfocusedLocationBarLayoutLeft + mLocationBarBackgroundLeftPosition;
-        }
-
         FrameLayout.LayoutParams locationBarLayoutParams = getFrameLayoutParams(mLocationBar);
         int currentLeftMargin = locationBarLayoutParams.leftMargin;
-        locationBarTranslationX -= (currentLeftMargin + mToolbarSidePadding);
+        int currentWidth = locationBarLayoutParams.width;
+
+        if (isLocationBarRtl) {
+            // The location bar contents should be aligned with the right side of the toolbar.
+            // If RTL text is displayed in an LTR toolbar, the right position of the location bar
+            // background will change as the location bar background expands/contracts.
+            locationBarTranslationX =
+                    -currentWidth + getRightPositionOfLocationBarBackground(mVisualState);
+
+            if (!mHasVisibleViewPriorToUrlBar) locationBarTranslationX -= mToolbarSidePadding;
+        } else {
+            // The location bar contents should be aligned with the left side of the location bar
+            // background. If LTR text is displayed in an RTL toolbar, the current left position of
+            // the location bar background will change as the location bar background
+            // expands/contracts.
+            locationBarTranslationX = mUnfocusedLocationBarLayoutLeft
+                    + getLeftPositionOfLocationBarBackground(mVisualState) - mToolbarSidePadding;
+        }
+
+        locationBarTranslationX -= currentLeftMargin;
 
         // Get the padding straight from the location bar instead of
         // |mLocationBarBackgroundPadding|, because it might be different in incognito mode.
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 f68ad99..160b79c 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
@@ -188,6 +188,8 @@
     protected boolean mLayoutLocationBarInFocusedMode;
     protected int mUnfocusedLocationBarLayoutWidth;
     protected int mUnfocusedLocationBarLayoutLeft;
+    protected int mUnfocusedLocationBarLayoutRight;
+    protected boolean mHasVisibleViewPriorToUrlBar;
     private boolean mUnfocusedLocationBarUsesTransparentBg;
 
     private int mLocationBarBackgroundAlpha = 255;
@@ -260,7 +262,7 @@
         NEW_TAB_NORMAL
     }
 
-    private VisualState mVisualState = VisualState.NORMAL;
+    protected VisualState mVisualState = VisualState.NORMAL;
     private VisualState mOverlayDrawablesVisualState;
     protected boolean mUseLightToolbarDrawables;
 
@@ -529,12 +531,12 @@
     }
 
     private void updateUnfocusedLocationBarLayoutParams() {
-        boolean hasVisibleViewPriorToUrlBar = false;
+        mHasVisibleViewPriorToUrlBar = false;
         for (int i = 0; i < mLocationBar.getChildCount(); i++) {
             View child = mLocationBar.getChildAt(i);
             if (child == mUrlBar) break;
             if (child.getVisibility() != GONE) {
-                hasVisibleViewPriorToUrlBar = true;
+                mHasVisibleViewPriorToUrlBar = true;
                 break;
             }
         }
@@ -542,7 +544,7 @@
         int leftViewBounds = getViewBoundsLeftOfLocationBar(mVisualState);
         int rightViewBounds = getViewBoundsRightOfLocationBar(mVisualState);
 
-        if (!hasVisibleViewPriorToUrlBar) {
+        if (!mHasVisibleViewPriorToUrlBar) {
             if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
                 rightViewBounds -= mToolbarSidePadding;
             } else {
@@ -561,6 +563,7 @@
 
         mUnfocusedLocationBarLayoutWidth = rightViewBounds - leftViewBounds;
         mUnfocusedLocationBarLayoutLeft = leftViewBounds;
+        mUnfocusedLocationBarLayoutRight = rightViewBounds;
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
index 3ce2934..34e16276 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.MetricsUtils;
@@ -50,6 +51,12 @@
         RequestThrottler.purgeAllEntriesForTesting(context);
         mClientManager = new ClientManager(context);
         RecordHistogram.initialize();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                OriginVerifier.reset();
+            }
+        });
     }
 
     @Test
@@ -162,53 +169,71 @@
     @Test
     @SmallTest
     public void testPostMessageOriginVerification() {
-        Assert.assertTrue(
-                mClientManager.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
+        final ClientManager cm = mClientManager;
+        Assert.assertTrue(cm.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
         // Should always start with no origin.
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // With no prepopulated origins, this verification should fail.
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                // With no prepopulated origins, this verification should fail.
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // If there is a prepopulated origin, we should get a synchronous verification.
-        OriginVerifier.prePopulateVerifiedOriginForTesting(
-                ContextUtils.getApplicationContext().getPackageName(), Uri.parse(URL));
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+                // If there is a prepopulated origin, we should get a synchronous verification.
+                OriginVerifier.addVerifiedOriginForPackage(
+                        ContextUtils.getApplicationContext().getPackageName(), Uri.parse(URL));
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+            }
+        });
+
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return mClientManager.getPostMessageOriginForSessionForTesting(mSession) != null;
+                return cm.getPostMessageOriginForSessionForTesting(mSession) != null;
             }
         });
-        Uri verifiedOrigin = mClientManager.getPostMessageOriginForSessionForTesting(mSession);
-        Assert.assertEquals(IntentHandler.ANDROID_APP_REFERRER_SCHEME, verifiedOrigin.getScheme());
 
-        // initializeWithPostMessageOriginForSession should override without checking origin.
-        mClientManager.initializeWithPostMessageOriginForSession(mSession, null);
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Uri verifiedOrigin = cm.getPostMessageOriginForSessionForTesting(mSession);
+                Assert.assertEquals(
+                        IntentHandler.ANDROID_APP_REFERRER_SCHEME, verifiedOrigin.getScheme());
+
+                // initializeWithPostMessageOriginForSession should override without checking
+                // origin.
+                cm.initializeWithPostMessageOriginForSession(mSession, null);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
+            }
+        });
     }
 
     @Test
     @SmallTest
     public void testPostMessageOriginHttpNotAllowed() {
-        Assert.assertTrue(
-                mClientManager.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
+        final ClientManager cm = mClientManager;
+        Assert.assertTrue(cm.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
         // Should always start with no origin.
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // With no prepopulated origins, this verification should fail.
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(HTTP_URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Uri uri = Uri.parse(HTTP_URL);
+                // With no prepopulated origins, this verification should fail.
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, uri);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // Even if there is a prepopulated origin, non-https origins should get an early return with
-        // false.
-        OriginVerifier.prePopulateVerifiedOriginForTesting(
-                ContextUtils.getApplicationContext().getPackageName(), Uri.parse(HTTP_URL));
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(HTTP_URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+                // Even if there is a prepopulated origin, non-https origins should get an early
+                // return with false.
+                OriginVerifier.addVerifiedOriginForPackage(
+                        ContextUtils.getApplicationContext().getPackageName(), uri);
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, uri);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
+            }
+        });
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index fb3871b6..40c5ba6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -203,7 +203,8 @@
                 ContextMenuManager contextMenuManager =
                         new ContextMenuManager(mActivityTestRule.getActivity(),
                                 mUiDelegate.getNavigationDelegate(), touchEnabledDelegate);
-                mRecyclerView.init(mUiConfig, contextMenuManager, mAdapter);
+                mRecyclerView.init(mUiConfig, contextMenuManager);
+                mRecyclerView.setAdapter(mAdapter);
 
                 mSuggestion = new SnippetArticleViewHolder(
                         mRecyclerView, contextMenuManager, mUiDelegate, mUiConfig);
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 6f97fcb..a47c5f5 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -53,6 +53,7 @@
     &kCCTBackgroundTab,
     &kCCTExternalLinkHandling,
     &kCCTPostMessageAPI,
+    &kCCTRedirectPreconnect,
     &kChromeHomeFeature,
     &kChromeHomeExpandButton,
     &kChromeHomeSwipeLogic,
@@ -135,6 +136,9 @@
 const base::Feature kCCTPostMessageAPI{"CCTPostMessageAPI",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kCCTRedirectPreconnect{"CCTRedirectPreconnect",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kChromeHomeFeature{"ChromeHome",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 350b8c8..8774253 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -19,6 +19,7 @@
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTExternalLinkHandling;
 extern const base::Feature kCCTPostMessageAPI;
+extern const base::Feature kCCTRedirectPreconnect;
 extern const base::Feature kChromeHomeFeature;
 extern const base::Feature kChromeHomeExpandButton;
 extern const base::Feature kChromeHomeSwipeLogic;
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 6b5e73b..eec47e0 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -698,14 +698,20 @@
     LoadAndLaunchPlatformApp("web_view/interstitial_teardown",
                              "EmbedderLoaded");
 
-    // Now load the guest.
+    // Create the guest.
     content::WebContents* embedder_web_contents =
         GetFirstAppWindowWebContents();
-    ExtensionTestMessageListener second("GuestAddedToDom", false);
+    ExtensionTestMessageListener guest_added("GuestAddedToDom", false);
+    EXPECT_TRUE(content::ExecuteScript(embedder_web_contents,
+                                       base::StringPrintf("createGuest();\n")));
+    ASSERT_TRUE(guest_added.WaitUntilSatisfied());
+
+    // Now load the guest.
+    ExtensionTestMessageListener guest_loaded("GuestLoaded", false);
     EXPECT_TRUE(content::ExecuteScript(
         embedder_web_contents,
         base::StringPrintf("loadGuest(%d);\n", host_and_port.port())));
-    ASSERT_TRUE(second.WaitUntilSatisfied());
+    ASSERT_TRUE(guest_loaded.WaitUntilSatisfied());
 
     // Wait for interstitial page to be shown in guest.
     content::WebContents* guest_web_contents =
@@ -1788,6 +1794,23 @@
             content::GetFocusedRenderWidgetHost(outer_web_contents));
 }
 
+// Test makes sure that the browser does not crash when a <webview> navigates
+// out of an interstitial.
+IN_PROC_BROWSER_TEST_P(WebViewTest, InterstitialPageDetach) {
+  InterstitialTestHelper();
+
+  content::WebContents* guest_web_contents =
+      GetGuestViewManager()->WaitForSingleGuestCreated();
+  EXPECT_TRUE(guest_web_contents->ShowingInterstitialPage());
+
+  // Navigate to about:blank.
+  content::TestNavigationObserver load_observer(guest_web_contents);
+  bool result = ExecuteScript(guest_web_contents,
+                              "window.location.assign('about:blank')");
+  EXPECT_TRUE(result);
+  load_observer.Wait();
+}
+
 // This test makes sure the browser process does not crash if app is closed
 // while an interstitial page is being shown in guest.
 IN_PROC_BROWSER_TEST_P(WebViewTest, InterstitialTeardown) {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index cbbefdc..581839d 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -12,6 +12,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -188,9 +189,16 @@
 // not accessing any global browser state while the code is running.
 scoped_refptr<base::SequencedTaskRunner>
 ChromeConfigurator::GetSequencedTaskRunner() const {
-  return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::BACKGROUND,
-       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+  constexpr base::TaskTraits traits = {
+      base::MayBlock(), base::TaskPriority::BACKGROUND,
+      base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
+#if defined(OS_WIN)
+  // Use the COM STA task runner as the Windows background downloader requires
+  // COM initialization.
+  return base::CreateCOMSTATaskRunnerWithTraits(traits);
+#else
+  return base::CreateSequencedTaskRunnerWithTraits(traits);
+#endif
 }
 
 PrefService* ChromeConfigurator::GetPrefService() const {
diff --git a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
index d5fc4c0..c9b31ff7 100644
--- a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/notifications/notification_channels_provider_android.h"
 
+#include <map>
+#include <vector>
+
 #include "base/memory/ptr_util.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/values.h"
@@ -20,52 +23,100 @@
 #include "url/gurl.h"
 
 using ::testing::_;
-using ::testing::InSequence;
-using ::testing::MockFunction;
-using ::testing::Return;
 
 namespace {
 const char kTestOrigin[] = "https://example.com";
 }  // namespace
 
-class MockNotificationChannelsBridge
+class FakeNotificationChannelsBridge
     : public NotificationChannelsProviderAndroid::NotificationChannelsBridge {
  public:
-  ~MockNotificationChannelsBridge() = default;
-  MOCK_METHOD0(ShouldUseChannelSettings, bool());
-  MOCK_METHOD2(CreateChannel, void(const std::string&, bool));
-  MOCK_METHOD1(GetChannelStatus, NotificationChannelStatus(const std::string&));
-  MOCK_METHOD1(DeleteChannel, void(const std::string&));
-  MOCK_METHOD0(GetChannels, std::vector<NotificationChannel>());
+  explicit FakeNotificationChannelsBridge(bool should_use_channels) {
+    should_use_channels_ = should_use_channels;
+  }
+
+  ~FakeNotificationChannelsBridge() override = default;
+
+  void SetChannelStatus(const std::string& origin,
+                        NotificationChannelStatus status) {
+    switch (status) {
+      case NotificationChannelStatus::UNAVAILABLE:
+        channels_.erase(origin);
+        return;
+      case NotificationChannelStatus::ENABLED:
+      case NotificationChannelStatus::BLOCKED:
+        auto entry = channels_.find(origin);
+        if (entry != channels_.end())
+          entry->second.status = status;
+        else
+          channels_.emplace(origin, NotificationChannel(origin, status));
+        return;
+    }
+  }
+
+  // NotificationChannelsBridge methods.
+
+  bool ShouldUseChannelSettings() override { return should_use_channels_; }
+
+  void CreateChannel(const std::string& origin, bool enabled) override {
+    // Note if a channel for the given origin was already created, this is a
+    // no-op. This is intentional, to match the Android Channels API.
+    channels_.emplace(
+        origin, NotificationChannel(
+                    origin, enabled ? NotificationChannelStatus::ENABLED
+                                    : NotificationChannelStatus::BLOCKED));
+  }
+
+  NotificationChannelStatus GetChannelStatus(
+      const std::string& origin) override {
+    auto entry = channels_.find(origin);
+    if (entry != channels_.end())
+      return entry->second.status;
+    return NotificationChannelStatus::UNAVAILABLE;
+  }
+
+  void DeleteChannel(const std::string& origin) override {
+    channels_.erase(origin);
+  }
+
+  std::vector<NotificationChannel> GetChannels() override {
+    std::vector<NotificationChannel> channels;
+    for (auto it = channels_.begin(); it != channels_.end(); it++)
+      channels.push_back(it->second);
+    return channels;
+  }
+
+ private:
+  bool should_use_channels_;
+  std::map<std::string, NotificationChannel> channels_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeNotificationChannelsBridge);
 };
 
 class NotificationChannelsProviderAndroidTest : public testing::Test {
  public:
-  NotificationChannelsProviderAndroidTest()
-      : mock_bridge_(new MockNotificationChannelsBridge()) {}
+  NotificationChannelsProviderAndroidTest() = default;
+
   ~NotificationChannelsProviderAndroidTest() override {
     channels_provider_->ShutdownOnUIThread();
   }
 
  protected:
   void InitChannelsProvider(bool should_use_channels) {
-    EXPECT_CALL(*mock_bridge_, ShouldUseChannelSettings())
-        .WillOnce(Return(should_use_channels));
-    ON_CALL(*mock_bridge_, GetChannelStatus(_))
-        .WillByDefault(Return(NotificationChannelStatus::UNAVAILABLE));
+    fake_bridge_ = new FakeNotificationChannelsBridge(should_use_channels);
 
     // Can't use base::MakeUnique because the provider's constructor is private.
     channels_provider_ =
         base::WrapUnique(new NotificationChannelsProviderAndroid(
-            base::WrapUnique(mock_bridge_)));
+            base::WrapUnique(fake_bridge_)));
   }
 
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
-  // No leak because ownership is passed to channels_provider_ in constructor.
-  MockNotificationChannelsBridge* mock_bridge_;
-
   std::unique_ptr<NotificationChannelsProviderAndroid> channels_provider_;
+
+  // No leak because ownership is passed to channels_provider_ in constructor.
+  FakeNotificationChannelsBridge* fake_bridge_;
 };
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -82,9 +133,6 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingAllowedWhenChannelUnavailable_CreatesEnabledChannel) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::UNAVAILABLE));
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, true /* enabled */));
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -92,14 +140,15 @@
       new base::Value(CONTENT_SETTING_ALLOW));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::ENABLED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingBlockedWhenChannelUnavailable_CreatesDisabledChannel) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::UNAVAILABLE));
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, false /* enabled */));
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -107,13 +156,16 @@
       new base::Value(CONTENT_SETTING_BLOCK));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::BLOCKED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingAllowedWhenChannelAllowed_NoopAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::ENABLED));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -121,13 +173,16 @@
       new base::Value(CONTENT_SETTING_ALLOW));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::ENABLED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingBlockedWhenChannelBlocked_NoopAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::BLOCKED));
+  fake_bridge_->CreateChannel(kTestOrigin, false);
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -135,17 +190,22 @@
       new base::Value(CONTENT_SETTING_BLOCK));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::BLOCKED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingDefault_DeletesChannelAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(kTestOrigin));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(), nullptr);
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(0u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -166,7 +226,6 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenNoChannelsExist) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannels());
   EXPECT_FALSE(channels_provider_->GetRuleIterator(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       false /* incognito */));
@@ -175,9 +234,8 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenOneBlockedChannelExists) {
   InitChannelsProvider(true /* should_use_channels */);
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back(kTestOrigin, NotificationChannelStatus::BLOCKED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel(kTestOrigin, false);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -193,9 +251,8 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenOneAllowedChannelExists) {
   InitChannelsProvider(true /* should_use_channels */);
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back(kTestOrigin, NotificationChannelStatus::ENABLED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -212,9 +269,9 @@
        GetRuleIteratorWhenMultipleChannelsExist) {
   InitChannelsProvider(true /* should_use_channels */);
   std::vector<NotificationChannel> channels;
-  channels.emplace_back("https://abc.com", NotificationChannelStatus::ENABLED);
-  channels.emplace_back("https://xyz.com", NotificationChannelStatus::BLOCKED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel("https://abc.com", true);
+  fake_bridge_->CreateChannel("https://xyz.com", false);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -239,56 +296,32 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  // Set up sequenced expectations. The observer should be notified on the first
-  // GetRuleIterator, and then only if channel status has changed to blocked.
-  // See "Using Check Points" section of the GTest Cookbook:
-  // https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#using-check-points
-  MockFunction<void(std::string check_point_name)> check;
-  {
-    InSequence s;
-    EXPECT_CALL(check, Call("0: GetRuleIterator never called"));
-    // Report channel as enabled initially.
-    std::vector<NotificationChannel> channels;
-    channels.emplace_back("https://example.com",
-                          NotificationChannelStatus::ENABLED);
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  // Create channel as enabled initially.
+  fake_bridge_->CreateChannel("https://example.com", true);
 
-    // Observer should be notified on first invocation of GetRuleIterator.
-    EXPECT_CALL(
-        mock_observer,
-        OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
-    EXPECT_CALL(check, Call("1: GetRuleIterator()"));
-
-    // Continue to report channel as enabled.
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
-
-    // Observer should not be notified this time.
-    EXPECT_CALL(check, Call("2: GetRuleIterator()"));
-
-    // Now report channel as blocked.
-    channels[0].status = NotificationChannelStatus::BLOCKED;
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
-
-    // GetRuleIterator should now notify observer.
-    EXPECT_CALL(
-        mock_observer,
-        OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
-    EXPECT_CALL(check, Call("3: GetRuleIterator()"));
-  }
-
-  check.Call("0: GetRuleIterator never called");
+  // Observer should be notified on first invocation of GetRuleIterator.
+  EXPECT_CALL(
+      mock_observer,
+      OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("1: GetRuleIterator()");
+
+  // Observer should not be notified the second time.
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("2: GetRuleIterator()");
+
+  // Now emulate user blocking the channel.
+  fake_bridge_->SetChannelStatus("https://example.com",
+                                 NotificationChannelStatus::BLOCKED);
+  // GetRuleIterator should now notify observer.
+  EXPECT_CALL(
+      mock_observer,
+      OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("3: GetRuleIterator()");
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -297,7 +330,6 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, true /* enabled */));
   EXPECT_CALL(
       mock_observer,
       OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
@@ -313,27 +345,33 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back("https://abc.com", NotificationChannelStatus::ENABLED);
-  channels.emplace_back("https://xyz.com", NotificationChannelStatus::BLOCKED);
-  ON_CALL(*mock_bridge_, GetChannels()).WillByDefault(Return(channels));
+  // Set up some channels.
+  fake_bridge_->SetChannelStatus("https://abc.com",
+                                 NotificationChannelStatus::ENABLED);
+  fake_bridge_->SetChannelStatus("https://xyz.com",
+                                 NotificationChannelStatus::BLOCKED);
 
-  EXPECT_CALL(*mock_bridge_, DeleteChannel("https://abc.com"));
-  EXPECT_CALL(*mock_bridge_, DeleteChannel("https://xyz.com"));
   EXPECT_CALL(mock_observer,
               OnContentSettingChanged(
                   ContentSettingsPattern(), ContentSettingsPattern(),
                   CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()));
+
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+
+  // Check channels were deleted.
+  EXPECT_EQ(0u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        ClearAllContentSettingsRulesNoopsForUnrelatedContentSettings) {
   InitChannelsProvider(true /* should_use_channels */);
 
-  EXPECT_CALL(*mock_bridge_, GetChannels()).Times(0);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(_)).Times(0);
+  // Set up some channels.
+  fake_bridge_->SetChannelStatus("https://abc.com",
+                                 NotificationChannelStatus::ENABLED);
+  fake_bridge_->SetChannelStatus("https://xyz.com",
+                                 NotificationChannelStatus::BLOCKED);
 
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_COOKIES);
@@ -341,15 +379,14 @@
       CONTENT_SETTINGS_TYPE_JAVASCRIPT);
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_GEOLOCATION);
+
+  // Check the channels still exist.
+  EXPECT_EQ(2u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        ClearAllContentSettingsRulesNoopsIfNotUsingChannels) {
   InitChannelsProvider(false /* should_use_channels */);
-
-  EXPECT_CALL(*mock_bridge_, GetChannels()).Times(0);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(_)).Times(0);
-
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
 }
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index ce61c46c..6f6b060b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -344,7 +344,7 @@
 
   // viewDidLoad became part of the API in 10.10.
   if (!base::mac::IsAtLeastOS10_10())
-    [self viewDidLoad];
+    [self viewDidLoadImpl];
 }
 
 - (BookmarkButton*)findAncestorButtonOnBarForNode:(const BookmarkNode*)node {
@@ -459,6 +459,12 @@
 }
 
 - (void)viewDidLoad {
+  // This indirection allows the viewDidLoad implementation to be called from
+  // elsewhere without triggering an availability warning.
+  [self viewDidLoadImpl];
+}
+
+- (void)viewDidLoadImpl {
   // We are enabled by default.
   barIsEnabled_ = YES;
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
index 2694ed0..9179b67 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
@@ -130,7 +130,7 @@
 
 // Fake a controller for callback ponging
 
-- (void)viewDidLoad {
+- (void)viewDidLoadImpl {
   // no-op
 }
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index 06775bb..a0b4a5e 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -107,7 +107,9 @@
   const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
   bool hasCustomThemeImage = themeProvider &&
       themeProvider->HasCustomImage(IDR_THEME_FRAME);
-  BOOL supportsVibrancy = [self visualEffectView] != nil;
+  BOOL supportsVibrancy = false;
+  if (@available(macOS 10.10, *))
+    supportsVibrancy = [self visualEffectView] != nil;
   BOOL isMainWindow = [[self window] isMainWindow];
 
   // If in Material Design mode, decrease the tabstrip background's translucency
@@ -353,7 +355,8 @@
   newTabButton_.reset([button retain]);
 }
 
-- (NSVisualEffectView*)visualEffectView {
+- (NSVisualEffectView*)visualEffectView
+    __attribute__((availability(macos, introduced = 10.10))) {
   return [[BrowserWindowController
       browserWindowControllerForWindow:[self window]] visualEffectView];
 }
@@ -367,21 +370,24 @@
 
   // Finish configuring the NSVisualEffectView so that it matches the window's
   // theme.
-  NSVisualEffectView* visualEffectView = [self visualEffectView];
-  const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
-  if (!visualEffectView || !themeProvider) {
-    return;
-  }
+  if (@available(macOS 10.10, *)) {
+    NSVisualEffectView* visualEffectView = [self visualEffectView];
+    const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
+    if (!visualEffectView || !themeProvider) {
+      return;
+    }
 
-  // Themes with custom frame images don't use vibrancy. Otherwise, if Incognito
-  // use Material Dark.
-  if (themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
-      themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
-    [visualEffectView setState:NSVisualEffectStateInactive];
-  } else if (themeProvider->InIncognitoMode()) {
-    [visualEffectView setMaterial:NSVisualEffectMaterialDark];
-    [visualEffectView setAppearance:
-        [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
+    // Themes with custom frame images don't use vibrancy. Otherwise, if
+    // Incognito use Material Dark.
+    if (themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
+        themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
+      [visualEffectView setState:NSVisualEffectStateInactive];
+    } else if (themeProvider->InIncognitoMode()) {
+      [visualEffectView setMaterial:NSVisualEffectMaterialDark];
+      [visualEffectView
+          setAppearance:[NSAppearance
+                            appearanceNamed:NSAppearanceNameVibrantDark]];
+    }
   }
 }
 
@@ -402,20 +408,22 @@
 }
 
 - (void)updateVisualEffectState {
-  // Configure the NSVisualEffectView so that it does nothing if the user has
-  // switched to a custom theme, or uses vibrancy if the user has switched back
-  // to the default theme.
-  NSVisualEffectView* visualEffectView = [self visualEffectView];
-  const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
-  if (!visualEffectView || !themeProvider) {
-    return;
-  }
-  if (visualEffectsDisabledForFullscreen_ ||
-      themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
-      themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
-    [visualEffectView setState:NSVisualEffectStateInactive];
-  } else {
-    [visualEffectView setState:NSVisualEffectStateFollowsWindowActiveState];
+  if (@available(macOS 10.10, *)) {
+    // Configure the NSVisualEffectView so that it does nothing if the user has
+    // switched to a custom theme, or uses vibrancy if the user has switched
+    // back to the default theme.
+    NSVisualEffectView* visualEffectView = [self visualEffectView];
+    const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
+    if (!visualEffectView || !themeProvider) {
+      return;
+    }
+    if (visualEffectsDisabledForFullscreen_ ||
+        themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
+        themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
+      [visualEffectView setState:NSVisualEffectStateInactive];
+    } else {
+      [visualEffectView setState:NSVisualEffectStateFollowsWindowActiveState];
+    }
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index 047226a4..1ffa5bf 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -242,7 +242,7 @@
 
     [self setWantsLayer:YES];  // -drawFill: needs a layer.
 
-    if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) {
+    if (@available(macOS 10.10, *)) {
       NSNotificationCenter* center =
           [[NSWorkspace sharedWorkspace] notificationCenter];
       [center
@@ -259,7 +259,7 @@
 - (void)dealloc {
   // Cancel any delayed requests that may still be pending (drags or hover).
   [NSObject cancelPreviousPerformRequestsWithTarget:self];
-  if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) {
+  if (@available(macOS 10.10, *)) {
     NSNotificationCenter* center =
         [[NSWorkspace sharedWorkspace] notificationCenter];
     [center removeObserver:self];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
index c088f4e1..fba29da 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -29,7 +29,9 @@
   base::scoped_nsobject<NSView> tabStripBackgroundView_;
 
   // Used to blur the titlebar. nil if window does not have titlebar.
-  base::scoped_nsobject<NSVisualEffectView> visualEffectView_;
+  __attribute__((availability(macos, introduced = 10.10)))
+  base::scoped_nsobject<NSVisualEffectView>
+      visualEffectView_;
 
   // The tab strip overlaps the titlebar of the window.
   base::scoped_nsobject<TabStripView> tabStripView_;
@@ -51,7 +53,10 @@
   base::scoped_nsobject<FocusTracker> focusBeforeOverlay_;
   BOOL closeDeferred_;  // If YES, call performClose: in removeOverlay:.
 }
-@property(readonly, nonatomic) NSVisualEffectView* visualEffectView;
+
+@property(readonly, nonatomic)
+    __attribute__((availability(macos, introduced=10.10)))
+    NSVisualEffectView* visualEffectView;
 @property(readonly, nonatomic) NSView* tabStripBackgroundView;
 @property(readonly, nonatomic) TabStripView* tabStripView;
 @property(readonly, nonatomic) FastResizeView* tabContentArea;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index 368f4e5..b524fd3 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -426,63 +426,64 @@
 
   // In Material Design on 10.10 and higher, the top portion of the window is
   // blurred using an NSVisualEffectView.
-  Class nsVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
-  if (!nsVisualEffectViewClass) {
+  if (@available(macOS 10.10, *)) {
+    [window setTitlebarAppearsTransparent:YES];
+
+    // If the window has a normal titlebar, then do not add NSVisualEffectView.
+    if (hasTitleBar)
+      return;
+
+    // NSVisualEffectView provides hints about text anti-aliasing that are wrong
+    // when anything is drawn over it (like a tint or theme image). Wrapping it
+    // stops it from being used for hints. See https://crbug.com/593835.
+    NSView* visualEffectWrapperView = [[[NSView alloc]
+        initWithFrame:[tabStripBackgroundView_ frame]] autorelease];
+
+    visualEffectView_.reset([[NSVisualEffectView alloc]
+        initWithFrame:visualEffectWrapperView.bounds]);
+    DCHECK(visualEffectView_);
+
+    [visualEffectWrapperView
+        setAutoresizingMask:[tabStripBackgroundView_ autoresizingMask]];
+    [visualEffectView_
+        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+    [tabStripBackgroundView_
+        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+    // Set to a default appearance and material. If this is an Incognito window
+    // the material and vibrancy should be dark but this method gets called at
+    // the start of -[BrowserWindowController initWithBrowser:takeOwnership:],
+    // before the |browser_| ivar has been set. Without a browser object we
+    // can't check the window's theme. The final setup happens in
+    // -[TabStripView setController:], at which point we have access to the
+    // theme.
+    [visualEffectView_
+        setAppearance:[NSAppearance
+                          appearanceNamed:NSAppearanceNameVibrantLight]];
+    [visualEffectView_ setMaterial:NSVisualEffectMaterialLight];
+    [visualEffectView_ setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
+    [visualEffectView_ setState:NSVisualEffectStateFollowsWindowActiveState];
+
+    [visualEffectWrapperView addSubview:visualEffectView_];
+
+    if (chrome::ShouldUseFullSizeContentView()) {
+      [[window contentView] addSubview:visualEffectWrapperView];
+    } else {
+      [rootView addSubview:visualEffectWrapperView
+                positioned:NSWindowBelow
+                relativeTo:nil];
+    }
+
+    // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView.
+    [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]];
+    [visualEffectView_ addSubview:tabStripBackgroundView_];
+  } else {
     DCHECK(!chrome::ShouldUseFullSizeContentView());
     [rootView addSubview:tabStripBackgroundView_
               positioned:NSWindowBelow
               relativeTo:nil];
     return;
   }
-
-  [window setTitlebarAppearsTransparent:YES];
-
-  // If the window has a normal titlebar, then do not add NSVisualEffectView.
-  if (hasTitleBar)
-    return;
-
-  // NSVisualEffectView provides hints about text anti-aliasing that are wrong
-  // when anything is drawn over it (like a tint or theme image). Wrapping it
-  // stops it from being used for hints. See https://crbug.com/593835.
-  NSView* visualEffectWrapperView = [[[NSView alloc]
-      initWithFrame:[tabStripBackgroundView_ frame]] autorelease];
-
-  visualEffectView_.reset([[nsVisualEffectViewClass alloc]
-      initWithFrame:visualEffectWrapperView.bounds]);
-  DCHECK(visualEffectView_);
-
-  [visualEffectWrapperView
-      setAutoresizingMask:[tabStripBackgroundView_ autoresizingMask]];
-  [visualEffectView_
-      setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-  [tabStripBackgroundView_
-      setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-  // Set to a default appearance and material. If this is an Incognito window
-  // the material and vibrancy should be dark but this method gets called at
-  // the start of -[BrowserWindowController initWithBrowser:takeOwnership:],
-  // before the |browser_| ivar has been set. Without a browser object we
-  // can't check the window's theme. The final setup happens in
-  // -[TabStripView setController:], at which point we have access to the theme.
-  [visualEffectView_ setAppearance:
-      [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
-  [visualEffectView_ setMaterial:NSVisualEffectMaterialLight];
-  [visualEffectView_ setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
-  [visualEffectView_ setState:NSVisualEffectStateFollowsWindowActiveState];
-
-  [visualEffectWrapperView addSubview:visualEffectView_];
-
-  if (chrome::ShouldUseFullSizeContentView()) {
-    [[window contentView] addSubview:visualEffectWrapperView];
-  } else {
-    [rootView addSubview:visualEffectWrapperView
-              positioned:NSWindowBelow
-              relativeTo:nil];
-  }
-
-  // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView.
-  [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]];
-  [visualEffectView_ addSubview:tabStripBackgroundView_];
 }
 
 // Called when the size of the window content area has changed. Override to
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index f5feee6..47814dc 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -248,10 +248,14 @@
 // reason is not guaranteed to be called (http://crbug.com/526276), so implement
 // both.
 - (void)awakeFromNib {
-  [self viewDidLoad];
+  [self viewDidLoadImpl];
 }
 
 - (void)viewDidLoad {
+  [self viewDidLoadImpl];
+}
+
+- (void)viewDidLoadImpl {
   // Temporary: collect information about a potentially missing or inaccessible
   // nib (https://crbug.com/685985)
   NSString* nibPath = [self.nibBundle pathForResource:@"Toolbar" ofType:@"nib"];
diff --git a/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
index 57475d88..1307f405 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
@@ -2,9 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+var webview;
+
+window.createGuest = function() {
+  webview = document.createElement('webview');
+  webview.src = 'about:blank';
+  document.body.appendChild(webview);
+  chrome.test.sendMessage('GuestAddedToDom');
+}
+
 window.loadGuest = function(port) {
   window.console.log('embedder.loadGuest: ' + port);
-  var webview = document.createElement('webview');
 
   // This page is not loaded, we just need a https URL.
   var guestSrcHTTPS = 'https://localhost:' + port +
@@ -16,8 +24,7 @@
   webview.style.left = '0px';
   webview.style.top = '0px';
 
-  document.body.appendChild(webview);
-  chrome.test.sendMessage('GuestAddedToDom');
+  chrome.test.sendMessage('GuestLoaded');
 };
 
 window.onload = function() {
diff --git a/chromeos/network/onc/onc_translator_onc_to_shill.cc b/chromeos/network/onc/onc_translator_onc_to_shill.cc
index 53e386d..cc3714d 100644
--- a/chromeos/network/onc/onc_translator_onc_to_shill.cc
+++ b/chromeos/network/onc/onc_translator_onc_to_shill.cc
@@ -156,16 +156,17 @@
   if (user_auth_type == ::onc::openvpn_user_auth_type::kOTP)
     CopyFieldFromONCToShill(::onc::openvpn::kOTP, shill::kOpenVPNTokenProperty);
 
-  // Shill supports only one RemoteCertKU but ONC a list.
-  // Copy only the first entry if existing.
-  const base::ListValue* cert_kus = NULL;
+  // Shill supports only one RemoteCertKU but ONC specifies a list, so copy only
+  // the first entry if the lists exists. Otherwise copy an empty string to
+  // reset any previous configuration.
+  const base::ListValue* cert_kus = nullptr;
   std::string cert_ku;
   if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
-                                               &cert_kus) &&
-      cert_kus->GetString(0, &cert_ku)) {
-    shill_dictionary_->SetStringWithoutPathExpansion(
-        shill::kOpenVPNRemoteCertKUProperty, cert_ku);
+                                               &cert_kus)) {
+    cert_kus->GetString(0, &cert_ku);
   }
+  shill_dictionary_->SetStringWithoutPathExpansion(
+      shill::kOpenVPNRemoteCertKUProperty, cert_ku);
 
   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
        it.Advance()) {
diff --git a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
index a8852a94..f7b3adda 100644
--- a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
+++ b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
@@ -6,6 +6,7 @@
   "OpenVPN.Password":"some password",
   "OpenVPN.Port":"443",
   "OpenVPN.Proto":"udp",
+  "OpenVPN.RemoteCertKU":"",
   "OpenVPN.User":"abc ${LOGIN_EMAIL} def",
   "Provider.Host":"vpn.my.domain.com",
   "Provider.Type":"openvpn",
diff --git a/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json b/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
index 15470fd6..afe264e 100644
--- a/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
+++ b/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
@@ -5,6 +5,7 @@
   "OpenVPN.Password":"some password",
   "OpenVPN.Port":"443",
   "OpenVPN.Proto":"udp",
+  "OpenVPN.RemoteCertKU":"",
   "OpenVPN.User":"abc ${LOGIN_EMAIL} def",
   "Provider.Host":"vpn.my.domain.com",
   "Provider.Type":"openvpn",
diff --git a/chromeos/test/data/network/shill_openvpn_clientcert.json b/chromeos/test/data/network/shill_openvpn_clientcert.json
index 437f0ad..65e9ef9 100644
--- a/chromeos/test/data/network/shill_openvpn_clientcert.json
+++ b/chromeos/test/data/network/shill_openvpn_clientcert.json
@@ -5,6 +5,7 @@
    "OpenVPN.Port": "1234",
    "OpenVPN.Proto": "udp",
    "OpenVPN.User": "hans",
+   "OpenVPN.RemoteCertKU":"",
    "Provider.Host": "terminus.muc",
    "Provider.Type": "openvpn",
    "ProxyConfig": "{\"mode\":\"direct\"}",
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 8024ba4..8f6d89d3 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -224,8 +224,6 @@
       "//components/tracing:unit_tests",
       "//components/translate/content/renderer:unit_tests",
       "//components/visitedlink/test:unit_tests",
-      "//components/viz/host:unit_tests",
-      "//components/viz/service:unit_tests",
       "//components/wallpaper:unit_tests",
       "//components/web_cache/browser:unit_tests",
       "//components/webcrypto:unit_tests",
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 230ecf0..4474e321 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1201,13 +1201,17 @@
 action("generate_licenses") {
   _license_path = "$_package_dir/LICENSE"
 
-  script = "//components/cronet/tools/cronet_licenses.py"
+  script = "//tools/licenses.py"
   outputs = [
     _license_path,
   ]
   args = [
-    "license",
+    "license_file",
     rebase_path(_license_path, root_build_dir),
+    "--gn-target",
+    "//components/cronet/android:cronet",
+    "--gn-out-dir",
+    ".",
   ]
 }
 
diff --git a/components/cronet/ios/cronet_environment.h b/components/cronet/ios/cronet_environment.h
index bed027b..31cec890 100644
--- a/components/cronet/ios/cronet_environment.h
+++ b/components/cronet/ios/cronet_environment.h
@@ -29,7 +29,7 @@
 namespace net {
 class CookieStore;
 class NetLog;
-class WriteToFileNetLogObserver;
+class FileNetLogObserver;
 }  // namespace net
 
 namespace cronet {
@@ -131,7 +131,7 @@
                                     const base::Closure& task);
 
   // Helper methods that start/stop net logging on the network thread.
-  void StartNetLogOnNetworkThread(base::ScopedFILE file, bool log_bytes);
+  void StartNetLogOnNetworkThread(const base::FilePath&, bool log_bytes);
   void StopNetLogOnNetworkThread(base::WaitableEvent* log_stopped_event);
 
   // Returns the HttpNetworkSession object from the passed in
@@ -169,7 +169,7 @@
   std::string user_agent_;
   bool user_agent_partial_;
   std::unique_ptr<net::NetLog> net_log_;
-  std::unique_ptr<net::WriteToFileNetLogObserver> net_log_observer_;
+  std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
   bool enable_pkp_bypass_for_local_trust_anchors_;
 
   DISALLOW_COPY_AND_ASSIGN(CronetEnvironment);
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index dd3c96f..609c180 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -8,11 +8,11 @@
 
 #include "base/at_exit.h"
 #include "base/atomicops.h"
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
 #include "base/json/json_writer.h"
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
@@ -37,9 +37,9 @@
 #include "net/http/http_stream_factory.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/http/http_util.h"
+#include "net/log/file_net_log_observer.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_capture_mode.h"
-#include "net/log/write_to_file_net_log_observer.h"
 #include "net/proxy/proxy_service.h"
 #include "net/quic/core/quic_versions.h"
 #include "net/socket/ssl_client_socket.h"
@@ -86,6 +86,10 @@
   DISALLOW_COPY_AND_ASSIGN(CronetURLRequestContextGetter);
 };
 
+void SignalEvent(base::WaitableEvent* event) {
+  event->Signal();
+}
+
 }  // namespace
 
 namespace cronet {
@@ -140,42 +144,34 @@
 
 bool CronetEnvironment::StartNetLog(base::FilePath::StringType file_name,
                                     bool log_bytes) {
-  if (!file_name.length())
+  if (file_name.empty())
     return false;
 
   base::FilePath path(file_name);
 
-  base::ScopedFILE file(base::OpenFile(path, "w"));
-  if (!file) {
-    LOG(ERROR) << "Can not start NetLog to " << path.value() << ": "
-               << strerror(errno);
-    return false;
-  }
-
   LOG(WARNING) << "Starting NetLog to " << path.value();
-  PostToNetworkThread(
-      FROM_HERE,
-      base::Bind(&CronetEnvironment::StartNetLogOnNetworkThread,
-                 base::Unretained(this), base::Passed(&file), log_bytes));
+  PostToNetworkThread(FROM_HERE,
+                      base::Bind(&CronetEnvironment::StartNetLogOnNetworkThread,
+                                 base::Unretained(this), path, log_bytes));
 
   return true;
 }
 
-void CronetEnvironment::StartNetLogOnNetworkThread(base::ScopedFILE file,
+void CronetEnvironment::StartNetLogOnNetworkThread(const base::FilePath& path,
                                                    bool log_bytes) {
   DCHECK(net_log_);
 
-  if (net_log_observer_)
+  if (file_net_log_observer_)
     return;
 
   net::NetLogCaptureMode capture_mode =
       log_bytes ? net::NetLogCaptureMode::IncludeSocketBytes()
                 : net::NetLogCaptureMode::Default();
 
-  net_log_observer_.reset(new net::WriteToFileNetLogObserver());
-  net_log_observer_->set_capture_mode(capture_mode);
-  net_log_observer_->StartObserving(main_context_->net_log(), std::move(file),
-                                    nullptr, main_context_.get());
+  file_net_log_observer_ =
+      net::FileNetLogObserver::CreateUnbounded(path, nullptr);
+  file_net_log_observer_->StartObserving(main_context_->net_log(),
+                                         capture_mode);
   LOG(WARNING) << "Started NetLog";
 }
 
@@ -191,12 +187,12 @@
 
 void CronetEnvironment::StopNetLogOnNetworkThread(
     base::WaitableEvent* log_stopped_event) {
-  if (net_log_observer_) {
+  if (file_net_log_observer_) {
     DLOG(WARNING) << "Stopped NetLog.";
-    net_log_observer_->StopObserving(main_context_.get());
-    net_log_observer_.reset();
+    file_net_log_observer_->StopObserving(
+        nullptr, base::BindOnce(&SignalEvent, log_stopped_event));
+    file_net_log_observer_.reset();
   }
-  log_stopped_event->Signal();
 }
 
 net::HttpNetworkSession* CronetEnvironment::GetHttpNetworkSession(
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 5ca4fee..ddc142a 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -22,6 +22,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
@@ -418,16 +419,11 @@
     GrGLTextureInfo texture_info;
     texture_info.fID = buffer->texture->get();
     texture_info.fTarget = GL_TEXTURE_2D;
-    GrBackendTextureDesc desc;
-    desc.fFlags = kRenderTarget_GrBackendTextureFlag;
-    desc.fWidth = width_;
-    desc.fHeight = height_;
-    desc.fConfig = kGrPixelConfig;
-    desc.fOrigin = kTopLeft_GrSurfaceOrigin;
-    desc.fTextureHandle = reinterpret_cast<GrBackendObject>(&texture_info);
-
+    GrBackendTexture backend_texture(width_, height_, kGrPixelConfig,
+                                     texture_info);
     buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
-        gr_context_.get(), desc, nullptr);
+        gr_context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
+        /* sampleCnt */ 0, /* colorSpace */ nullptr, /* props */ nullptr);
     DCHECK(buffer->sk_surface);
     return buffer;
   }
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index 1339cc1..aced3bb3 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -432,19 +432,27 @@
 }
 
 void ContentSuggestionsService::SetRemoteSuggestionsEnabled(bool enabled) {
-  pref_service_->SetBoolean(prefs::kEnableSnippets, enabled);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsEnabled() const {
-  return pref_service_->GetBoolean(prefs::kEnableSnippets);
+  return !remote_suggestions_provider_->IsDisabled();
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsManaged() const {
-  return pref_service_->IsManagedPreference(prefs::kEnableSnippets);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
+  return false;
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsManagedByCustodian() const {
-  return pref_service_->IsPreferenceManagedByCustodian(prefs::kEnableSnippets);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider.h b/components/ntp_snippets/remote/remote_suggestions_provider.h
index 5e94b8a..a2b76f5 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider.h
@@ -41,6 +41,9 @@
   virtual GURL GetUrlWithFavicon(
       const ContentSuggestion::ID& suggestion_id) const = 0;
 
+  // Whether the service is explicity disabled.
+  virtual bool IsDisabled() const = 0;
+
  protected:
   RemoteSuggestionsProvider(Observer* observer);
 };
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index 877d27d..c13ee94 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -348,6 +348,10 @@
   return ContentSuggestion::GetFaviconDomain(suggestion->url());
 }
 
+bool RemoteSuggestionsProviderImpl::IsDisabled() const {
+  return state_ == State::DISABLED;
+}
+
 void RemoteSuggestionsProviderImpl::FetchSuggestions(
     bool interactive_request,
     const FetchStatusCallback& callback) {
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index 1941a49c..ef70fc4 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -94,6 +94,8 @@
   GURL GetUrlWithFavicon(
       const ContentSuggestion::ID& suggestion_id) const override;
 
+  bool IsDisabled() const override;
+
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
index 715bfb3..e59eb4a 100644
--- a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -81,6 +81,7 @@
                      const RemoteSuggestionsFetcher*());
   MOCK_CONST_METHOD1(GetUrlWithFavicon,
                      GURL(const ContentSuggestion::ID& suggestion_id));
+  MOCK_CONST_METHOD0(IsDisabled, bool());
   MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
   MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
   MOCK_METHOD3(ClearHistory,
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index ed4e99b..38fc464 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -14,6 +14,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/google/core/browser/google_util.h"
 #include "components/ntp_tiles/constants.h"
diff --git a/components/ntp_tiles/popular_sites_impl_unittest.cc b/components/ntp_tiles/popular_sites_impl_unittest.cc
index 419483e..d29217f2 100644
--- a/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/ntp_tiles/constants.h"
 #include "components/ntp_tiles/json_unsafe_parser.h"
 #include "components/ntp_tiles/pref_names.h"
diff --git a/components/viz/BUILD.gn b/components/viz/BUILD.gn
new file mode 100644
index 0000000..e02e4340
--- /dev/null
+++ b/components/viz/BUILD.gn
@@ -0,0 +1,24 @@
+# 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.
+
+import("//testing/test.gni")
+
+test("viz_unittests") {
+  sources = [
+    "run_all_unittests.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/viz/host:unit_tests",
+    "//components/viz/service:unit_tests",
+    "//mojo/edk/system",
+    "//ui/gl:test_support",
+  ]
+
+  if (!is_android) {
+    deps += [ "//components/viz/common:unit_tests" ]
+  }
+}
diff --git a/components/viz/DEPS b/components/viz/DEPS
new file mode 100644
index 0000000..565ba60
--- /dev/null
+++ b/components/viz/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/edk/embedder",
+  "+ui/gl",
+]
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index f60c6674..a72063a 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -31,20 +31,15 @@
   ]
 }
 
+# These tests don't pass on Android so this target isn't in viz_unittests. If
+# you add a test here that should run on Android you need to change that.
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "resources/platform_color_unittest.cc",
+    "gl_helper_unittest.cc",
     "yuv_readback_unittest.cc",
   ]
 
-  if (!is_android) {
-    sources += [
-      # Many of these fail on Android with the test GL implementation.
-      "gl_helper_unittest.cc",
-    ]
-  }
-
   deps = [
     ":common",
     "//base/test:test_support",
diff --git a/components/viz/host/server_gpu_memory_buffer_manager.cc b/components/viz/host/server_gpu_memory_buffer_manager.cc
index ac36c93..afbc5e14 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager.cc
@@ -171,9 +171,9 @@
   if (iter == allocated_buffers_[client_id].end())
     return;
   DCHECK_NE(gfx::EMPTY_BUFFER, iter->second.type);
-  allocated_buffers_[client_id].erase(id);
   if (iter->second.type != gfx::SHARED_MEMORY_BUFFER)
     gpu_service_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
+  allocated_buffers_[client_id].erase(id);
 }
 
 void ServerGpuMemoryBufferManager::DestroyAllGpuMemoryBufferForClient(
diff --git a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
index 5d5e60b2..97ad09a 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/viz/host/server_gpu_memory_buffer_manager.h"
 
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
 #include "services/ui/gpu/interfaces/gpu_service.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -225,7 +226,7 @@
   } configs[] = {
       {gfx::BufferUsage::SCANOUT, gfx::BufferFormat::YVU_420, {10, 20}, true},
       {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::ATC, {10, 20}, true},
-      {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {10, 20}, false},
+      {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {64, 64}, false},
   };
   for (const auto& config : configs) {
     gfx::GpuMemoryBufferHandle allocated_handle;
@@ -255,4 +256,28 @@
   }
 }
 
+TEST_F(ServerGpuMemoryBufferManagerTest, GpuMemoryBufferDestroyed) {
+  gfx::ClientNativePixmapFactory::ResetInstance();
+  TestGpuService gpu_service;
+  ServerGpuMemoryBufferManager manager(&gpu_service, 1);
+  base::Thread diff_thread("TestThread");
+  ASSERT_TRUE(diff_thread.Start());
+  std::unique_ptr<gfx::GpuMemoryBuffer> buffer;
+  base::RunLoop run_loop;
+  ASSERT_TRUE(diff_thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(
+                     [](ServerGpuMemoryBufferManager* manager,
+                        std::unique_ptr<gfx::GpuMemoryBuffer>* out_buffer,
+                        const base::Closure& callback) {
+                       *out_buffer = manager->CreateGpuMemoryBuffer(
+                           gfx::Size(64, 64), gfx::BufferFormat::YVU_420,
+                           gfx::BufferUsage::GPU_READ, gpu::kNullSurfaceHandle);
+                       callback.Run();
+                     },
+                     &manager, &buffer, run_loop.QuitClosure())));
+  run_loop.Run();
+  EXPECT_TRUE(buffer);
+  buffer.reset();
+}
+
 }  // namespace viz
diff --git a/components/viz/run_all_unittests.cc b/components/viz/run_all_unittests.cc
new file mode 100644
index 0000000..03910b9
--- /dev/null
+++ b/components/viz/run_all_unittests.cc
@@ -0,0 +1,38 @@
+// 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 "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "ui/gl/test/gl_surface_test_support.h"
+
+namespace {
+
+class VizTestSuite : public base::TestSuite {
+ public:
+  VizTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {}
+  ~VizTestSuite() override = default;
+
+  // base::TestSuite:
+  void Initialize() override {
+    base::TestSuite::Initialize();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VizTestSuite);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  VizTestSuite test_suite(argc, argv);
+
+  mojo::edk::Init();
+
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&VizTestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index db6deec..eeb15ca 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -6870,4 +6870,118 @@
             controller.GetLastCommittedEntry()->GetURL().spec());
 }
 
+// If the main frame does a load, it should not be reported as a subframe
+// navigation. This used to occur in the following case:
+// 1. You're on a site with frames.
+// 2. You do a subframe navigation. This was stored with transition type
+//    MANUAL_SUBFRAME.
+// 3. You navigate to some non-frame site.
+// 4. You navigate back to the page from step 2. Since it was initially
+//    MANUAL_SUBFRAME, it will be that same transition type here.
+// We don't want that, because any navigation that changes the toplevel frame
+// should be tracked as a toplevel navigation (this allows us to update the URL
+// bar, etc).
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       GoBackToManualSubFrame) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/navigation_controller/page_with_iframe.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  ASSERT_EQ(1U, root->child_count());
+  ASSERT_NE(nullptr, root->child_at(0));
+
+  {
+    // Iframe initial load.
+    LoadCommittedCapturer capturer(root->child_at(0));
+    GURL frame_url(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_1.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
+  }
+
+  {
+    // Iframe manual navigation.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    GURL frame_url(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_2.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
+  }
+
+  {
+    // Main frame navigation.
+    FrameNavigateParamsCapturer capturer(root);
+    GURL main_url_2(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_2.html"));
+    NavigateFrameToURL(root, main_url_2);
+    capturer.Wait();
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(), ui::PAGE_TRANSITION_LINK));
+  }
+
+  {
+    // Check the history before going back.
+    NavigationControllerImpl& controller =
+        static_cast<NavigationControllerImpl&>(
+            shell()->web_contents()->GetController());
+    EXPECT_EQ(3, controller.GetEntryCount());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(0)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    // TODO(creis, arthursonzogni): The correct PageTransition is still an open
+    // question. Maybe PAGE_TRANSITION_MANUAL_SUBFRAME is more appropriate.
+    // Please see https://crbug.com/740461.
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(1)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(2)->GetTransitionType(),
+        ui::PAGE_TRANSITION_LINK));
+  }
+
+  {
+    // Back.
+    FrameNavigateParamsCapturer capturer(root);
+    shell()->web_contents()->GetController().GoBack();
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FORWARD_BACK |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+  }
+
+  {
+    // Check the history again.
+    NavigationControllerImpl& controller =
+        static_cast<NavigationControllerImpl&>(
+            shell()->web_contents()->GetController());
+    EXPECT_EQ(3, controller.GetEntryCount());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(0)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(1)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FORWARD_BACK |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(2)->GetTransitionType(),
+        ui::PAGE_TRANSITION_LINK));
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 25940df..f66dac33 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1039,30 +1039,10 @@
 }
 
 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
-  // The logic below is weaker than "are all sites isolated" -- it asks instead,
-  // "is any site isolated". That's appropriate here since we're just trying to
-  // figure out if we're in any kind of site isolated mode, and in which case,
-  // we ignore the kSingleProcess and kProcessPerTab settings.
-  //
-  // TODO(nick): Move all handling of kSingleProcess/kProcessPerTab into
-  // SiteIsolationPolicy so we have a consistent behavior around the interaction
-  // of the process model flags.
-  //
-  // TODO(creis, alexmos): This looks like it will break single-process and
-  // process-per-tab.  See https://crbug.com/688617.
-  if (SiteIsolationPolicy::AreCrossProcessFramesPossible())
-    return true;
-
-  // False in the single-process mode, as it makes RVHs to accumulate
-  // in swapped_out_hosts_.
-  // True if we are using process-per-site-instance (default) or
-  // process-per-site (kProcessPerSite).
-  // TODO(nick): Move handling of kSingleProcess and kProcessPerTab into
-  // SiteIsolationPolicy.
+  // False in single-process mode, which does not support cross-process
+  // navigations or OOPIFs.
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kSingleProcess) &&
-         !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kProcessPerTab);
+      switches::kSingleProcess);
 }
 
 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index df0c3eda..8dc24708 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -560,8 +560,8 @@
   void DeleteRenderFrameProxyHost(SiteInstance* site_instance);
 
   // Returns whether this tab should transition to a new renderer for
-  // cross-site URLs.  Enabled unless we see the --process-per-tab command line
-  // switch.  Can be overridden in unit tests.
+  // cross-site URLs.  Enabled unless we see the --single-process command line
+  // switch.
   bool ShouldTransitionCrossSite();
 
   // Returns true if for the navigation from |current_effective_url| to
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 7a5ed8e4..08cb4e3c 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/site_instance_impl.h"
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "content/browser/browsing_instance.h"
@@ -16,6 +17,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host_factory.h"
 #include "content/public/browser/web_ui_controller_factory.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
@@ -434,6 +436,12 @@
 // static
 bool SiteInstanceImpl::ShouldLockToOrigin(BrowserContext* browser_context,
                                           GURL site_url) {
+  // Don't lock to origin in --single-process mode, since this mode puts
+  // cross-site pages into the same process.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess))
+    return false;
+
   if (!DoesSiteRequireDedicatedProcess(browser_context, site_url))
     return false;
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index c2854649..5163e7d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2922,7 +2922,18 @@
 }
 
 void WebContentsImpl::DetachInterstitialPage() {
-  // Disconnect from outer WebContents if necessary.
+  bool interstitial_pausing_throbber =
+      ShowingInterstitialPage() && interstitial_page_->pause_throbber();
+  if (ShowingInterstitialPage())
+    interstitial_page_ = nullptr;
+  for (auto& observer : observers_)
+    observer.DidDetachInterstitialPage();
+
+  // Disconnect from outer WebContents if necessary. This must happen after the
+  // interstitial page is cleared above, since the call to
+  // SetRWHViewForInnerContents below may loop over all the
+  // RenderWidgetHostViews in the tree (otherwise, including the now-deleted
+  // view for the interstitial).
   if (node_.OuterContentsFrameTreeNode()) {
     if (GetRenderManager()->GetProxyToOuterDelegate()) {
       DCHECK(static_cast<RenderWidgetHostViewBase*>(
@@ -2935,13 +2946,6 @@
     }
   }
 
-  bool interstitial_pausing_throbber =
-      ShowingInterstitialPage() && interstitial_page_->pause_throbber();
-  if (ShowingInterstitialPage())
-    interstitial_page_ = nullptr;
-  for (auto& observer : observers_)
-    observer.DidDetachInterstitialPage();
-
   // Restart the throbber if needed now that the interstitial page is going
   // away.
   if (interstitial_pausing_throbber && frame_tree_.IsLoading())
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 6a0e423..5409b6dd 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -720,6 +720,9 @@
 // renderer process.  We default to using a renderer process for each
 // site instance (i.e., group of pages from the same registered domain with
 // script connections to each other).
+// TODO(creis): This flag is currently a no-op.  We should refactor it to avoid
+// "unnecessary" process swaps for cross-site navigations but still swap when
+// needed for security (e.g., isolated origins).
 const char kProcessPerTab[]                 = "process-per-tab";
 
 // The value of this switch determines whether the process is started as a
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index d0dc5c7c..7e70eafe 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4947,20 +4947,7 @@
     params.contents_mime_type = ds->GetResponse().MimeType().Utf8();
 
     params.transition = navigation_state->GetTransitionType();
-    if (!ui::PageTransitionIsMainFrame(params.transition)) {
-      // If the main frame does a load, it should not be reported as a subframe
-      // navigation.  This can occur in the following case:
-      // 1. You're on a site with frames.
-      // 2. You do a subframe navigation.  This is stored with transition type
-      //    MANUAL_SUBFRAME.
-      // 3. You navigate to some non-frame site, say, google.com.
-      // 4. You navigate back to the page from step 2.  Since it was initially
-      //    MANUAL_SUBFRAME, it will be that same transition type here.
-      // We don't want that, because any navigation that changes the toplevel
-      // frame should be tracked as a toplevel navigation (this allows us to
-      // update the URL bar, etc).
-      params.transition = ui::PAGE_TRANSITION_LINK;
-    }
+    DCHECK(ui::PageTransitionIsMainFrame(params.transition));
 
     // If the page contained a client redirect (meta refresh, document.loc...),
     // set the transition appropriately.
diff --git a/extensions/browser/updater/update_client_config.cc b/extensions/browser/updater/update_client_config.cc
index fd18447b..8c21593c 100644
--- a/extensions/browser/updater/update_client_config.cc
+++ b/extensions/browser/updater/update_client_config.cc
@@ -6,6 +6,8 @@
 
 #include "base/sequenced_task_runner.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "build/build_config.h"
 
 namespace extensions {
 
@@ -13,9 +15,16 @@
 
 scoped_refptr<base::SequencedTaskRunner>
 UpdateClientConfig::GetSequencedTaskRunner() const {
-  return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::BACKGROUND,
-       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  constexpr base::TaskTraits traits = {
+      base::MayBlock(), base::TaskPriority::BACKGROUND,
+      base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
+#if defined(OS_WIN)
+  // Use the COM STA task runner as the Windows background downloader requires
+  // COM initialization.
+  return base::CreateCOMSTATaskRunnerWithTraits(traits);
+#else
+  return base::CreateSequencedTaskRunnerWithTraits(traits);
+#endif
 }
 
 UpdateClientConfig::~UpdateClientConfig() {}
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index fc0f7fd..fa67855 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -7094,7 +7094,7 @@
   def WriteGetDataSizeCode(self, func, f):
     """Overrriden from TypeHandler."""
     code = """  uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(%s), %d, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<%s, %d>(1, &data_size)) {
     return error::kOutOfBounds;
   }
 """
@@ -7392,7 +7392,7 @@
     """Overrriden from TypeHandler."""
     code = """  uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(%s), %d, &data_size)) {
+      !GLES2Util::ComputeDataSize<%s, %d>(count, &data_size)) {
     return error::kOutOfBounds;
   }
 """
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 8172e224..0a451f6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1820,22 +1820,6 @@
   return format;
 }
 
-// static
-bool GLES2Util::ComputeDataSize(uint32_t count,
-                                size_t size,
-                                unsigned int elements_per_unit,
-                                uint32_t* dst) {
-  uint32_t value;
-  if (!SafeMultiplyUint32(count, static_cast<uint32_t>(size), &value)) {
-    return false;
-  }
-  if (!SafeMultiplyUint32(value, elements_per_unit, &value)) {
-    return false;
-  }
-  *dst = value;
-  return true;
-}
-
 namespace {
 
 // GL context configuration attributes. Those in the 16-bit range are the same
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index f3dc765..e1b0c6ff 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -252,10 +252,12 @@
       uint32_t internal_format, uint32_t type, int* r, int* g, int* b, int* a);
 
   // Computes the data size for certain gl commands like glUniform.
-  static bool ComputeDataSize(uint32_t count,
-                              size_t size,
-                              unsigned int elements_per_unit,
-                              uint32_t* dst);
+  template <typename VALUE_TYPE, unsigned int ELEMENTS_PER_UNIT>
+  static bool ComputeDataSize(uint32_t count, uint32_t* dst) {
+    constexpr uint32_t element_size = sizeof(VALUE_TYPE) * ELEMENTS_PER_UNIT;
+    return base::CheckMul(count, element_size)
+        .template AssignIfValid<uint32_t>(dst);
+  }
 
 #include "gpu/command_buffer/common/gles2_cmd_utils_autogen.h"
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 8f57edf9..6b776d9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3179,6 +3179,10 @@
   context_ = context;
   surface_ = surface;
 
+  // Set workarounds for the surface.
+  surface_->SetRelyOnImplicitSync(
+      workarounds().rely_on_implicit_sync_for_swap_buffers);
+
   // Create GPU Tracer for timing values.
   gpu_tracer_.reset(new GPUTracer(this));
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 25237e2..fef99fa 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -387,7 +387,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -417,7 +417,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -447,7 +447,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2134,8 +2134,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2173,8 +2172,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2529,7 +2527,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2577,7 +2575,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2881,7 +2879,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2933,7 +2931,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3054,7 +3052,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3091,8 +3089,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3136,8 +3133,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3179,7 +3175,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3220,8 +3216,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3266,8 +3261,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3310,7 +3304,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3352,8 +3346,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3399,8 +3392,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3444,7 +3436,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3487,8 +3479,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3535,8 +3526,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3566,7 +3556,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3598,7 +3588,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3630,7 +3620,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3660,7 +3650,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 9>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3692,7 +3682,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3724,7 +3714,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3754,7 +3744,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 16>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3786,7 +3776,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3818,7 +3808,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3875,7 +3865,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3910,7 +3900,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 2>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3946,7 +3936,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 3>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3983,7 +3973,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4024,7 +4014,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4065,7 +4055,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4655,7 +4645,7 @@
       const volatile gles2::cmds::ProduceTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4685,7 +4675,7 @@
   GLuint texture = c.texture;
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4712,7 +4702,7 @@
       const volatile gles2::cmds::ConsumeTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4741,7 +4731,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLuint texture = static_cast<GLuint>(c.texture);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4833,8 +4823,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4888,8 +4877,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4916,8 +4904,7 @@
                        ScheduleCALayerInUseQueryCHROMIUMImmediate*>(cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4973,7 +4960,7 @@
 
   GLenum matrixMode = static_cast<GLenum>(c.matrixMode);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -5116,7 +5103,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -5155,8 +5142,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 629a24d..8a2d17d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -307,7 +307,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -334,7 +334,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -361,7 +361,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -1736,8 +1736,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -1767,8 +1766,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2120,7 +2118,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2162,7 +2160,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2338,7 +2336,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2380,7 +2378,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2471,7 +2469,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2511,8 +2509,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2552,8 +2549,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2595,7 +2591,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2636,8 +2632,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2678,8 +2673,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2722,7 +2716,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2764,8 +2758,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2807,8 +2800,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2852,7 +2844,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2895,8 +2887,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2939,8 +2930,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2969,7 +2959,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2998,7 +2988,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3027,7 +3017,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3056,7 +3046,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 9>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3085,7 +3075,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3114,7 +3104,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3143,7 +3133,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 16>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3172,7 +3162,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3201,7 +3191,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3267,7 +3257,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3308,7 +3298,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 2>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3350,7 +3340,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 3>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3393,7 +3383,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3436,7 +3426,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3479,7 +3469,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3908,7 +3898,7 @@
       const volatile gles2::cmds::ProduceTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3937,7 +3927,7 @@
   GLuint texture = c.texture;
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3962,7 +3952,7 @@
       const volatile gles2::cmds::ConsumeTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3990,7 +3980,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLuint texture = static_cast<GLuint>(c.texture);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4076,8 +4066,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4118,8 +4107,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4146,8 +4134,7 @@
                        ScheduleCALayerInUseQueryCHROMIUMImmediate*>(cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4206,7 +4193,7 @@
           cmd_data);
   GLenum matrixMode = static_cast<GLenum>(c.matrixMode);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4319,7 +4306,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4367,8 +4354,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index d20ca2f..9576577 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -1,6 +1,6 @@
 {
   "name": "gpu driver bug list",
-  "version": "10.16",
+  "version": "10.17",
   "entries": [
     {
       "id": 1,
@@ -2552,6 +2552,18 @@
       "disabled_extensions": [
         "EGL_EXT_image_flush_external"
       ]
+    },
+    {
+      "id": 235,
+      "description": "Avoid waiting on a egl fence before pageflipping and rely on implicit sync.",
+      "cr_bugs": [721463],
+      "os": {
+        "type": "chromeos"
+      },
+      "gl_vendor": "Intel.*",
+      "features": [
+        "rely_on_implicit_sync_for_swap_buffers"
+      ]
     }
   ],
   "comment": [
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index f252881..ffe1402 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -225,6 +225,8 @@
          validate_multisample_buffer_allocation)             \
   GPU_OP(WAKE_UP_GPU_BEFORE_DRAWING,                         \
          wake_up_gpu_before_drawing)                         \
+  GPU_OP(RELY_ON_IMPLICIT_SYNC_FOR_SWAP_BUFFERS,             \
+         rely_on_implicit_sync_for_swap_buffers)             \
 // clang-format on
 
 namespace gpu {
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index 5806909..e453735 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -472,6 +472,9 @@
   [toolsCell.reloadButton removeTarget:self.dispatcher
                                 action:@selector(reload)
                       forControlEvents:UIControlEventTouchUpInside];
+  [toolsCell.shareButton removeTarget:self.dispatcher
+                               action:@selector(sharePage)
+                     forControlEvents:UIControlEventTouchUpInside];
   [toolsCell.starButton removeTarget:self.dispatcher
                               action:@selector(bookmarkPage)
                     forControlEvents:UIControlEventTouchUpInside];
@@ -595,6 +598,9 @@
     [cell.reloadButton addTarget:self.dispatcher
                           action:@selector(reload)
                 forControlEvents:UIControlEventTouchUpInside];
+    [cell.shareButton addTarget:self.dispatcher
+                         action:@selector(sharePage)
+               forControlEvents:UIControlEventTouchUpInside];
     [cell.starButton addTarget:self.dispatcher
                         action:@selector(bookmarkPage)
               forControlEvents:UIControlEventTouchUpInside];
diff --git a/ios/showcase/BUILD.gn b/ios/showcase/BUILD.gn
index e4f750da..daf76b1f 100644
--- a/ios/showcase/BUILD.gn
+++ b/ios/showcase/BUILD.gn
@@ -35,6 +35,7 @@
     "//ios/showcase/settings",
     "//ios/showcase/tab",
     "//ios/showcase/tab_grid",
+    "//ios/showcase/text_badge_view",
     "//ios/showcase/toolbar",
     "//ios/showcase/tools_menu",
     "//ios/showcase/uikit_table_view_cell",
@@ -75,6 +76,7 @@
     "//ios/showcase/root:eg_tests",
     "//ios/showcase/tab:eg_tests",
     "//ios/showcase/tab_grid:eg_tests",
+    "//ios/showcase/text_badge_view:eg_tests",
     "//ios/showcase/toolbar:eg_tests",
 
     # All shared libraries must have the sanitizer deps to properly link in
diff --git a/ios/showcase/core/showcase_model.mm b/ios/showcase/core/showcase_model.mm
index f974949..d9431ae 100644
--- a/ios/showcase/core/showcase_model.mm
+++ b/ios/showcase/core/showcase_model.mm
@@ -91,6 +91,11 @@
       showcase::kClassForInstantiationKey : @"SCContentWidgetCoordinator",
       showcase::kUseCaseKey : @"Content Widget",
     },
+    @{
+      showcase::kClassForDisplayKey : @"TextBadgeView",
+      showcase::kClassForInstantiationKey : @"SCTextBadgeViewController",
+      showcase::kUseCaseKey : @"Text badge view",
+    },
   ];
 }
 
diff --git a/ios/showcase/text_badge_view/BUILD.gn b/ios/showcase/text_badge_view/BUILD.gn
new file mode 100644
index 0000000..ab9a4f03
--- /dev/null
+++ b/ios/showcase/text_badge_view/BUILD.gn
@@ -0,0 +1,26 @@
+source_set("text_badge_view") {
+  sources = [
+    "sc_text_badge_view_controller.h",
+    "sc_text_badge_view_controller.mm",
+  ]
+  deps = [
+    "//ios/chrome/browser/ui/reading_list:reading_list_ui",
+  ]
+  libs = [ "UIKit.framework" ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "sc_text_badge_view_egtest.mm",
+  ]
+  deps = [
+    "//ios/chrome/browser/ui/reading_list:reading_list_ui",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/showcase/test",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/showcase/text_badge_view/sc_text_badge_view_controller.h b/ios/showcase/text_badge_view/sc_text_badge_view_controller.h
new file mode 100644
index 0000000..a4fcb33
--- /dev/null
+++ b/ios/showcase/text_badge_view/sc_text_badge_view_controller.h
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_SHOWCASE_TEXT_BADGE_VIEW_SC_TEXT_BADGE_VIEW_CONTROLLER_H_
+#define IOS_SHOWCASE_TEXT_BADGE_VIEW_SC_TEXT_BADGE_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+@interface SCTextBadgeViewController : UIViewController
+@end
+
+#endif  // IOS_SHOWCASE_TEXT_BADGE_VIEW_SC_TEXT_BADGE_VIEW_CONTROLLER_H_
diff --git a/ios/showcase/text_badge_view/sc_text_badge_view_controller.mm b/ios/showcase/text_badge_view/sc_text_badge_view_controller.mm
new file mode 100644
index 0000000..1c99fa3
--- /dev/null
+++ b/ios/showcase/text_badge_view/sc_text_badge_view_controller.mm
@@ -0,0 +1,24 @@
+// 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.
+
+#import "ios/showcase/text_badge_view/sc_text_badge_view_controller.h"
+
+#import "ios/chrome/browser/ui/reading_list/text_badge_view.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation SCTextBadgeViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  self.view.backgroundColor = [UIColor grayColor];
+  TextBadgeView* textBadge = [[TextBadgeView alloc] initWithText:@"TEXT"];
+  [self.view addSubview:textBadge];
+  textBadge.bounds = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
+  textBadge.center = self.view.center;
+}
+
+@end
diff --git a/ios/showcase/text_badge_view/sc_text_badge_view_egtest.mm b/ios/showcase/text_badge_view/sc_text_badge_view_egtest.mm
new file mode 100644
index 0000000..b9fb9a3
--- /dev/null
+++ b/ios/showcase/text_badge_view/sc_text_badge_view_egtest.mm
@@ -0,0 +1,30 @@
+// 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.
+
+#import <EarlGrey/EarlGrey.h>
+
+#import "ios/showcase/test/showcase_eg_utils.h"
+#import "ios/showcase/test/showcase_test_case.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+using ::showcase_utils::Open;
+using ::showcase_utils::Close;
+}
+
+@interface TextBadgeViewTestCase : ShowcaseTestCase
+@end
+
+@implementation TextBadgeViewTestCase
+
+// Tests that the accessibility label matches the display text.
+- (void)testTextBadgeAccessibilityLabel {
+  Open(@"TextBadgeView");
+  Close();
+}
+
+@end
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn
index 8ef6f7c..048c35b 100644
--- a/net/android/BUILD.gn
+++ b/net/android/BUILD.gn
@@ -53,6 +53,7 @@
   testonly = true
   java_files = [
     "../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java",
+    "../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java",
     "../test/android/javatests/src/org/chromium/net/test/util/CertTestUtil.java",
     "../test/android/javatests/src/org/chromium/net/test/util/NetworkChangeNotifierTestUtil.java",
     "../test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java",
@@ -62,6 +63,8 @@
     ":net_java",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/android_support_test_runner:runner_java",
     "//third_party/android_tools:android_support_annotations_java",
     "//third_party/junit",
   ]
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java
new file mode 100644
index 0000000..2288f27
--- /dev/null
+++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java
@@ -0,0 +1,44 @@
+// 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.
+
+package org.chromium.net.test;
+
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+/**
+ * Junit4 rule for starting embedded test server before a test starts, and shutting it down when it
+ * finishes.
+ */
+public class EmbeddedTestServerRule extends TestWatcher {
+    EmbeddedTestServer mServer = new EmbeddedTestServer();
+
+    @Override
+    protected void starting(Description description) {
+        try {
+            EmbeddedTestServer.initializeAndStartServer(
+                    mServer, InstrumentationRegistry.getContext());
+        } catch (InterruptedException e) {
+            throw new EmbeddedTestServer.EmbeddedTestServerFailure("Test server didn't start");
+        }
+        super.starting(description);
+    }
+
+    @Override
+    protected void finished(Description description) {
+        super.finished(description);
+        mServer.stopAndDestroyServer();
+    }
+
+    /**
+     * Get the test server.
+     *
+     * @return the test server.
+     */
+    public EmbeddedTestServer getServer() {
+        return mServer;
+    }
+}
diff --git a/remoting/android/java/AndroidManifest.xml.jinja2 b/remoting/android/java/AndroidManifest.xml.jinja2
index 073cd33..01cb776 100644
--- a/remoting/android/java/AndroidManifest.xml.jinja2
+++ b/remoting/android/java/AndroidManifest.xml.jinja2
@@ -2,7 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="{{ APK_PACKAGE_NAME }}">
     <uses-sdk android:minSdkVersion="14"
-            android:targetSdkVersion="24"/>
+            android:targetSdkVersion="26"/>
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />
diff --git a/remoting/ios/client_gestures.mm b/remoting/ios/client_gestures.mm
index 00e5900c..0dbb9dc 100644
--- a/remoting/ios/client_gestures.mm
+++ b/remoting/ios/client_gestures.mm
@@ -30,7 +30,11 @@
   UIPanGestureRecognizer* _panRecognizer;
   UIPanGestureRecognizer* _flingRecognizer;
   UIPanGestureRecognizer* _scrollRecognizer;
-  UIPanGestureRecognizer* _threeFingerPanRecognizer;
+
+  // TODO(yuweih): Commented out because this makes two-finger gestures not
+  // quite responsive. Clean these up if it's really unnecessary.
+  //  UIPanGestureRecognizer* _threeFingerPanRecognizer;
+
   UIPinchGestureRecognizer* _pinchRecognizer;
   UITapGestureRecognizer* _singleTapRecognizer;
   UITapGestureRecognizer* _twoFingerTapRecognizer;
@@ -79,13 +83,13 @@
   _scrollRecognizer.delegate = self;
   [view addGestureRecognizer:_scrollRecognizer];
 
-  _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
-      initWithTarget:self
-              action:@selector(threeFingerPanGestureTriggered:)];
-  _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
-  _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
-  _threeFingerPanRecognizer.delegate = self;
-  [view addGestureRecognizer:_threeFingerPanRecognizer];
+  //  _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
+  //      initWithTarget:self
+  //              action:@selector(threeFingerPanGestureTriggered:)];
+  //  _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
+  //  _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
+  //  _threeFingerPanRecognizer.delegate = self;
+  //  [view addGestureRecognizer:_threeFingerPanRecognizer];
 
   _pinchRecognizer = [[UIPinchGestureRecognizer alloc]
       initWithTarget:self
@@ -117,10 +121,11 @@
   [_twoFingerTapRecognizer
       requireGestureRecognizerToFail:_threeFingerTapRecognizer];
   [_pinchRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
-  [_pinchRecognizer requireGestureRecognizerToFail:_threeFingerPanRecognizer];
+  //  [_pinchRecognizer
+  //  requireGestureRecognizerToFail:_threeFingerPanRecognizer];
   [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
-  [_threeFingerPanRecognizer
-      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
+  //  [_threeFingerPanRecognizer
+  //      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
   [_panRecognizer requireGestureRecognizerToFail:_scrollRecognizer];
 
   return self;
diff --git a/services/OWNERS b/services/OWNERS
index f5ec3de..82541da 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,3 +1,6 @@
 ben@chromium.org
+blundell@chromium.org
 jam@chromium.org
 rockot@chromium.org
+sky@chromium.org
+yzshen@chromium.org
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 78405b7..7406636 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -30,7 +30,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -187,7 +187,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -659,7 +659,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -738,7 +738,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -816,7 +816,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -894,7 +894,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1284,7 +1284,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1323,7 +1323,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1362,7 +1362,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1401,7 +1401,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1440,7 +1440,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1498,6 +1498,36 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "4",
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -1518,7 +1548,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -2803,6 +2833,38 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "KTU84Z",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -3996,6 +4058,38 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "LMY48I",
+              "device_type": "hammerhead"
+            }
+          ],
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -5381,6 +5475,38 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "LMY49B",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -5479,7 +5605,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -5642,7 +5768,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6477,7 +6603,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6557,7 +6683,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6637,7 +6763,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6677,7 +6803,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6837,7 +6963,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6877,7 +7003,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6917,7 +7043,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6957,7 +7083,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6997,7 +7123,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -7101,6 +7227,37 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "4",
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -7121,7 +7278,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -8383,6 +8540,38 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "MRA58Z",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "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": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2217e8b..7958a7a 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -481,6 +481,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -849,6 +855,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1207,6 +1219,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index dccc7c8..7e81889 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1529,6 +1529,36 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "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": "viz_unittests"
+      },
+      {
         "args": [
           "--gs-results-bucket=chromium-result-details"
         ],
@@ -3133,6 +3163,36 @@
         "test": "unit_tests"
       },
       {
+        "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": [
+            {
+              "android_devices": "1",
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "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": "viz_unittests"
+      },
+      {
         "args": [
           "--gs-results-bucket=chromium-result-details"
         ],
@@ -4198,6 +4258,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -4882,6 +4948,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
@@ -5265,6 +5337,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index dfcf46b..8cbb9f8d 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -386,6 +386,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -824,6 +830,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -1272,6 +1284,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -1679,6 +1697,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -2067,6 +2091,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 052b4ec..8fc1420 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -600,6 +600,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ]
   },
@@ -911,6 +917,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1234,6 +1246,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1509,6 +1527,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -1732,6 +1756,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 2cf5a44..de45ea8 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -455,6 +455,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
@@ -1015,6 +1021,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1540,6 +1552,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -2005,6 +2023,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 2a4d679..b79229b 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1069,6 +1069,10 @@
     "label": "//ui/views:views_unittests",
     "type": "windowed_test_launcher",
   },
+  "viz_unittests": {
+    "label": "//components/viz:viz_unittests",
+    "type": "windowed_test_launcher",
+  },
   "vr_common_unittests": {
     "label": "//chrome/browser/android/vr_shell:vr_common_unittests",
     "type": "console_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
index e9e146b2..bda480b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 5193 tests; 4986 PASS, 207 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 5193 tests; 4987 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver 
 PASS Document interface: attribute domain 
 PASS Document interface: attribute referrer 
@@ -592,7 +592,7 @@
 PASS HTMLElement interface: attribute onmouseout 
 PASS HTMLElement interface: attribute onmouseover 
 PASS HTMLElement interface: attribute onmouseup 
-FAIL HTMLElement interface: attribute onwheel assert_own_property: expected property "onwheel" missing
+PASS HTMLElement interface: attribute onwheel 
 PASS HTMLElement interface: attribute onpause 
 PASS HTMLElement interface: attribute onplay 
 PASS HTMLElement interface: attribute onplaying 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
index f2866e5..8e87cc47 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 300 tests; 291 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 292 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS onabort: must be on the appropriate locations for GlobalEventHandlers 
 PASS onabort: the default value must be null 
 PASS onabort: the content attribute must be compiled into a function as the corresponding property 
@@ -205,7 +205,7 @@
 PASS onmouseup: the content attribute must be compiled into a function as the corresponding property 
 PASS onmouseup: the content attribute must execute when an event is dispatched 
 PASS onmouseup: dispatching an Event at a <meta> element must trigger element.onmouseup 
-FAIL onwheel: must be on the appropriate locations for GlobalEventHandlers assert_true: HTMLElement has an own property named "onwheel" expected true got false
+PASS onwheel: must be on the appropriate locations for GlobalEventHandlers 
 PASS onwheel: the default value must be null 
 PASS onwheel: the content attribute must be compiled into a function as the corresponding property 
 PASS onwheel: the content attribute must execute when an event is dispatched 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
index fb226662..b56484b 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
@@ -703,5 +703,16 @@
 PASS Enumerate Document.onwaiting 
 PASS Set Window.onwaiting 
 PASS Enumerate Window.onwaiting 
+PASS No Element.onwheel 
+PASS Set HTMLElement.onwheel 
+PASS Enumerate HTMLElement.onwheel 
+PASS Reflect HTMLElement.onwheel 
+PASS Set SVGElement.onwheel 
+PASS Enumerate SVGElement.onwheel 
+PASS Reflect SVGElement.onwheel 
+PASS Set Document.onwheel 
+PASS Enumerate Document.onwheel 
+PASS Set Window.onwheel 
+PASS Enumerate Window.onwheel 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
index 4417478..0092151 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
@@ -69,7 +69,8 @@
     "ontouchmove",
     "ontouchstart",
     "onvolumechange",
-    "onwaiting"
+    "onwaiting",
+    "onwheel"
 ].forEach(function(attribute) {
     test(function() {
         assert_false(attribute in getObject("Element"));
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
index f75fda5a..6dfe0dd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE ERROR: [Report Only] Refused to load the image 'ftp://blah.test/' because it violates the following Content Security Policy directive: "img-src http://* https://*".
 
 PingLoader dispatched to 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/save-report.php?test=multiple-report-policies-1'.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
index 0f6d4a39..f57ae31 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE WARNING: Subresource requests whose URLs contain embedded credentials (e.g. `https://user:pass@host/`) are blocked. See https://www.chromestatus.com/feature/5669008342777856 for more details.
 This is a testharness.js-based test.
 PASS Untitled 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS
new file mode 100644
index 0000000..95fbf480
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+# Web-exposed API changes may require approval from blink API OWNERS.
+# See http://www.chromium.org/blink#new-features for details.
+file://third_party/WebKit/API_OWNERS
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
index 4757310..1535972 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1357,7 +1357,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1432,7 +1431,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -1975,6 +1973,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2066,6 +2065,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -4789,6 +4789,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -4870,6 +4871,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index 65eb1cda..85eae6c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1286,7 +1286,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1361,7 +1360,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -1904,6 +1902,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -1995,6 +1994,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -4718,6 +4718,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -4799,6 +4800,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/LayoutTests/security/block-test-expected.txt b/third_party/WebKit/LayoutTests/security/block-test-expected.txt
index 233c9b8..8ab4eae0 100644
--- a/third_party/WebKit/LayoutTests/security/block-test-expected.txt
+++ b/third_party/WebKit/LayoutTests/security/block-test-expected.txt
@@ -131,7 +131,7 @@
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:65536/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:4294967295/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:4294967296/test.jpg
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255:21/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255:22/test.jpg
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 6fce2fc..d2571f6 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -1815,7 +1815,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1895,7 +1894,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -2466,6 +2464,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2559,6 +2558,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -5567,6 +5567,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -5648,6 +5649,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
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 befa5470..b255d09 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1815,7 +1815,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1895,7 +1894,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -2466,6 +2464,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2559,6 +2558,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -5574,6 +5574,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -5655,6 +5656,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 03947a0c..bb06568 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -302,7 +302,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(securitypolicyviolation);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectionchange);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   bool ShouldMergeWithLegacyDescription(ViewportDescription::Type) const;
   bool ShouldOverrideLegacyDescription(ViewportDescription::Type) const;
diff --git a/third_party/WebKit/Source/core/dom/Document.idl b/third_party/WebKit/Source/core/dom/Document.idl
index 5b72874..3a74b3e8 100644
--- a/third_party/WebKit/Source/core/dom/Document.idl
+++ b/third_party/WebKit/Source/core/dom/Document.idl
@@ -210,7 +210,6 @@
     [RuntimeEnabled=ExperimentalContentSecurityPolicyFeatures] attribute EventHandler onsecuritypolicyviolation;
     attribute EventHandler onselectionchange;
     attribute EventHandler onselectstart;
-    attribute EventHandler onwheel;
 };
 
 Document implements GlobalEventHandlers;
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index ba33318..4139fb3 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -140,7 +140,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   bool hasAttribute(const QualifiedName&) const;
   const AtomicString& getAttribute(const QualifiedName&) const;
diff --git a/third_party/WebKit/Source/core/dom/Element.idl b/third_party/WebKit/Source/core/dom/Element.idl
index fa0e969..49f64bb 100644
--- a/third_party/WebKit/Source/core/dom/Element.idl
+++ b/third_party/WebKit/Source/core/dom/Element.idl
@@ -142,7 +142,6 @@
     attribute EventHandler onpaste;
     attribute EventHandler onsearch;
     attribute EventHandler onselectstart;
-    attribute EventHandler onwheel;
 };
 
 Element implements ParentNode;
diff --git a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
index 462e3cdc..24b34330 100644
--- a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
+++ b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
@@ -108,6 +108,7 @@
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(touchstart);
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(volumechange);
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(waiting);
+DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(wheel);
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
index 902056d..6735073b 100644
--- a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
+++ b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
@@ -94,6 +94,7 @@
     attribute EventHandler ontoggle;
     attribute EventHandler onvolumechange;
     attribute EventHandler onwaiting;
+    attribute EventHandler onwheel;
 
     // auxclick
     // https://wicg.github.io/auxclick/
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 348a1e2..1307f400 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -252,7 +252,7 @@
     case WebFeature::kLegacyProtocolEmbeddedAsSubresource:
       return String::Format(
           "Subresource requests using legacy protocols (like `ftp:`) are "
-          "are blocked. Please deliver web-accessible resources over modern "
+          "blocked. Please deliver web-accessible resources over modern "
           "protocols like HTTPS. See "
           "https://www.chromestatus.com/feature/5709390967472128 for details.");
 
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
index 1045dbd..814d7ab 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
@@ -247,7 +247,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(animationstart);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(transitionend);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationstart,
                                          webkitAnimationStart);
diff --git a/third_party/WebKit/Source/core/frame/Window.idl b/third_party/WebKit/Source/core/frame/Window.idl
index f1b8629..3e488fa 100644
--- a/third_party/WebKit/Source/core/frame/Window.idl
+++ b/third_party/WebKit/Source/core/frame/Window.idl
@@ -198,7 +198,6 @@
     attribute EventHandler onwebkitanimationiteration;
     attribute EventHandler onwebkitanimationstart;
     attribute EventHandler onwebkittransitionend;
-    attribute EventHandler onwheel;
 
     // https://w3c.github.io/webappsec/specs/powerfulfeatures/#monkey-patching-global-object
     readonly attribute boolean isSecureContext;
diff --git a/tools/licenses.py b/tools/licenses.py
index 9f33ffb8..ee65177c 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -493,7 +493,7 @@
     third_party_deps = set()
     for build_dep in gn_deps.split():
         m = re.search(r'^(.+/third_party/[^/]+)/(.+/)?BUILD\.gn$', build_dep)
-        if m:
+        if m and not os.path.join('build', 'secondary') in build_dep:
             third_party_deps.add(m.group(1))
     return third_party_deps
 
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index ad9b94ac..9978c171 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -50,5 +50,6 @@
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        pass # No tests disabled.
+        self.PermanentlyDisableBenchmark([story.expectations.ALL_MOBILE],
+                                         'Desktop benchmark.')
     return StoryExpectations()
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 8c6d262..8d4bf832 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -660,8 +660,7 @@
 
 }  // namespace
 
-class GestureRecognizerTest : public AuraTestBase,
-                              public ::testing::WithParamInterface<bool> {
+class GestureRecognizerTest : public AuraTestBase {
  public:
   GestureRecognizerTest() {}
 
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index f89a699..3c99f3b 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -194,6 +194,10 @@
   // By default, just executing the SwapBuffers is normally enough.
 }
 
+void GLSurface::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  NOTIMPLEMENTED();
+}
+
 GLSurface* GLSurface::GetCurrent() {
   return current_surface_.Pointer()->Get();
 }
@@ -397,6 +401,10 @@
   surface_->WaitForSnapshotRendering();
 }
 
+void GLSurfaceAdapter::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  surface_->SetRelyOnImplicitSync(rely_on_implicit_sync);
+}
+
 GLSurfaceAdapter::~GLSurfaceAdapter() {}
 
 scoped_refptr<GLSurface> InitializeGLSurfaceWithFormat(
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 2b24c76d..c93a61e 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -225,6 +225,10 @@
   // calling this.
   virtual void WaitForSnapshotRendering();
 
+  // Tells the surface to rely on implicit or explicit sync when swapping
+  // buffers.
+  virtual void SetRelyOnImplicitSync(bool rely_on_implicit_sync);
+
   static GLSurface* GetCurrent();
 
  protected:
@@ -298,6 +302,7 @@
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   gfx::Vector2d GetDrawOffset() const override;
   void WaitForSnapshotRendering() override;
+  void SetRelyOnImplicitSync(bool rely_on_implicit_sync) override;
 
   GLSurface* surface() const { return surface_.get(); }
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 7c3cba7..8f2b739 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -115,6 +115,15 @@
   frame->callback = surface_swap_callback;
   unsubmitted_frames_.push_back(base::MakeUnique<PendingFrame>());
 
+  // TODO(dcastagna): Remove the following workaround once we get explicit sync
+  // on Intel.
+  // We can not rely on implicit sync on external devices (crbug.com/692508).
+  if (rely_on_implicit_sync_ && !IsOnExternalDrmDevice()) {
+    frame->ready = true;
+    SubmitFrame();
+    return;
+  }
+
   // TODO: the following should be replaced by a per surface flush as it gets
   // implemented in GL drivers.
   EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
@@ -167,6 +176,10 @@
   return config_;
 }
 
+void GbmSurfaceless::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  rely_on_implicit_sync_ = rely_on_implicit_sync;
+}
+
 GbmSurfaceless::~GbmSurfaceless() {
   Destroy();  // The EGL surface must be destroyed before SurfaceOzone.
   surface_factory_->UnregisterSurface(window_->widget());
@@ -235,4 +248,8 @@
   SubmitFrame();
 }
 
+bool GbmSurfaceless::IsOnExternalDrmDevice() {
+  return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish();
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 1ec916ca..a12fcfa0 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -54,6 +54,7 @@
                           int height,
                           const SwapCompletionCallback& callback) override;
   EGLConfig GetConfig() override;
+  void SetRelyOnImplicitSync(bool rely_on_implicit_sync) override;
 
  protected:
   ~GbmSurfaceless() override;
@@ -82,6 +83,8 @@
   void SwapCompleted(const SwapCompletionCallback& callback,
                      gfx::SwapResult result);
 
+  bool IsOnExternalDrmDevice();
+
   GbmSurfaceFactory* surface_factory_;
   std::unique_ptr<DrmWindowProxy> window_;
   std::vector<OverlayPlane> planes_;
@@ -93,6 +96,7 @@
   bool has_implicit_external_sync_;
   bool last_swap_buffers_result_ = true;
   bool swap_buffers_pending_ = false;
+  bool rely_on_implicit_sync_ = false;
 
   base::WeakPtrFactory<GbmSurfaceless> weak_factory_;