diff --git a/DEPS b/DEPS
index 568c1e88..19cd2cb 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,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': '2ef4525daf153fe8927727e2131a35d520e90269',
+  'skia_revision': '33f02edb14bb2ad802324daa99886709990893a1',
   # 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': '6e9cb6944b56cc88ed142e1779cc53aa2ce37db2',
+  'v8_revision': '2943c641a94a3b5e5847f3549af11a8df03cd8cd',
   # 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.
@@ -139,7 +139,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': '767f070f1df4536e1d5be94ac04153a553b9c5f2',
+  'catapult_revision': '6b8f67cc144c8bfe103c7a84227e57ed33a20c31',
   # 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/PRESUBMIT.py b/PRESUBMIT.py
index e539b70..199158e6 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -658,6 +658,49 @@
     return []
 
 
+def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
+  """This is a simplified version of
+  _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
+  """
+  javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
+  javadoc_end_re = input_api.re.compile(r'^\s*\*/')
+  name_pattern = r'ForTest(s|ing)?'
+  # Describes an occurrence of "ForTest*" inside a // comment.
+  comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
+  # Catch calls.
+  inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
+  # Ignore definitions. (Comments are ignored separately.)
+  exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
+
+  problems = []
+  sources = lambda x: input_api.FilterSourceFile(
+    x,
+    black_list=(('(?i).*test', r'.*\/junit\/')
+                + input_api.DEFAULT_BLACK_LIST),
+    white_list=(r'.*\.java$',)
+  )
+  for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
+    local_path = f.LocalPath()
+    is_inside_javadoc = False
+    for line_number, line in f.ChangedContents():
+      if is_inside_javadoc and javadoc_end_re.search(line):
+        is_inside_javadoc = False
+      if not is_inside_javadoc and javadoc_start_re.search(line):
+        is_inside_javadoc = True
+      if is_inside_javadoc:
+        continue
+      if (inclusion_re.search(line) and
+          not comment_re.search(line) and
+          not exclusion_re.search(line)):
+        problems.append(
+          '%s:%d\n    %s' % (local_path, line_number, line.strip()))
+
+  if problems:
+    return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
+  else:
+    return []
+
+
 def _CheckNoIOStreamInHeaders(input_api, output_api):
   """Checks to make sure no .h files include <iostream>."""
   files = []
@@ -2667,6 +2710,8 @@
 
   results.extend(
       _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
+  results.extend(
+      _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
   results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
   results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
   results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index eba421c0..886d802 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -1591,5 +1591,52 @@
     self.assertEqual(0, len(results))
 
 
+class NoProductionJavaCodeUsingTestOnlyFunctions(unittest.TestCase):
+  def testTruePositives(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('dir/java/src/foo.java', ['FooForTesting();']),
+      MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
+      MockFile('dir/java/src/baz.java', ['FooForTest(','y',');']),
+      MockFile('dir/java/src/mult.java', [
+        'int x = SomethingLongHere()',
+        '    * SomethingLongHereForTesting();'
+      ]),
+    ]
+
+    results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctionsJava(
+        mock_input_api, MockOutputApi())
+    self.assertEqual(1, len(results))
+    self.assertEqual(4, len(results[0].items))
+    self.assertTrue('foo.java' in results[0].items[0])
+    self.assertTrue('bar.java' in results[0].items[1])
+    self.assertTrue('baz.java' in results[0].items[2])
+    self.assertTrue('mult.java' in results[0].items[3])
+
+  def testFalsePositives(self):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
+      MockFile('dir/java/src/foo.java', ['FooForTests() {']),
+      MockFile('dir/java/src/bar.java', ['// FooForTest();']),
+      MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
+      MockFile('dir/javatests/src/baz.java', ['FooForTest(','y',');']),
+      MockFile('dir/junit/src/baz.java', ['FooForTest(','y',');']),
+      MockFile('dir/junit/src/javadoc.java', [
+        '/** Use FooForTest(); to obtain foo in tests.'
+        ' */'
+      ]),
+      MockFile('dir/junit/src/javadoc2.java', [
+        '/** ',
+        ' * Use FooForTest(); to obtain foo in tests.'
+        ' */'
+      ]),
+    ]
+
+    results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctionsJava(
+        mock_input_api, MockOutputApi())
+    self.assertEqual(0, len(results))
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/WATCHLISTS b/WATCHLISTS
index 6a802881..768d471 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1503,6 +1503,10 @@
     'tools_win_chromeexts': {
       'filepath': 'tools/win/chromeexts',
     },
+    'touch_selection': {
+      'filepath': 'ui/touch_selection/'\
+                  '|content/public/android/java/src/org/chromium/content/browser/selection/'
+    },
     'tracing': {
       'filepath': 'base/debug/trace_event.*'\
                   '|base/trace_event/'\
@@ -2303,6 +2307,8 @@
                            'yusukes+watch@chromium.org'],
     'timers': ['chirantan+watch@chromium.org'],
     'tools_win_chromeexts': ['robliao+watch@chromium.org'],
+    'touch_selection': ['ajith.v@samsung.com',
+                        'ajith.v@chromium.org'],
     'tracing': ['tracing+reviews@chromium.org',
                 'wfh+watch@chromium.org'],
     'ui_compositor': ['cc-bugs@chromium.org'],
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index 709b8ed..3495dce 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -417,7 +417,7 @@
   web_prefs->ignore_main_frame_overflow_hidden_quirk = support_quirks;
   web_prefs->report_screen_size_in_physical_pixels_quirk = support_quirks;
 
-  web_prefs->resue_global_for_unowned_main_frame =
+  web_prefs->reuse_global_for_unowned_main_frame =
       Java_AwSettings_getAllowEmptyDocumentPersistenceLocked(env, obj);
 
   web_prefs->password_echo_enabled =
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 81780c5..b8d38e9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -339,8 +339,8 @@
     private boolean mIsViewVisible;
     private boolean mIsWindowVisible;
     private boolean mIsAttachedToWindow;
-    // Visiblity state of |mContentViewCore|.
-    private boolean mIsContentViewCoreVisible;
+    // Visiblity state of |mWebContents|.
+    private boolean mIsContentVisible;
     private boolean mIsUpdateVisibilityTaskPending;
     private Runnable mUpdateVisibilityRunnable;
 
@@ -2613,14 +2613,14 @@
     private void updateContentViewCoreVisibility() {
         mIsUpdateVisibilityTaskPending = false;
         if (isDestroyedOrNoOperation(NO_WARN)) return;
-        boolean contentViewCoreVisible = nativeIsVisible(mNativeAwContents);
+        boolean contentVisible = nativeIsVisible(mNativeAwContents);
 
-        if (contentViewCoreVisible && !mIsContentViewCoreVisible) {
-            mContentViewCore.onShow();
-        } else if (!contentViewCoreVisible && mIsContentViewCoreVisible) {
-            mContentViewCore.onHide();
+        if (contentVisible && !mIsContentVisible) {
+            mWebContents.onShow();
+        } else if (!contentVisible && mIsContentVisible) {
+            mWebContents.onHide();
         }
-        mIsContentViewCoreVisible = contentViewCoreVisible;
+        mIsContentVisible = contentVisible;
         updateChildProcessImportance();
     }
 
@@ -2632,7 +2632,7 @@
      */
     @VisibleForTesting
     public boolean isPageVisible() {
-        if (isDestroyedOrNoOperation(NO_WARN)) return mIsContentViewCoreVisible;
+        if (isDestroyedOrNoOperation(NO_WARN)) return mIsContentVisible;
         return nativeIsVisible(mNativeAwContents);
     }
 
@@ -2779,7 +2779,7 @@
     private void updateChildProcessImportance() {
         @ChildProcessImportance
         int effectiveImportance = ChildProcessImportance.IMPORTANT;
-        if (mRendererPriorityWaivedWhenNotVisible && !mIsContentViewCoreVisible) {
+        if (mRendererPriorityWaivedWhenNotVisible && !mIsContentVisible) {
             effectiveImportance = ChildProcessImportance.NORMAL;
         } else {
             switch (mRendererPriority) {
diff --git a/android_webview/support_library/OWNERS b/android_webview/support_library/OWNERS
new file mode 100644
index 0000000..80aa022f4
--- /dev/null
+++ b/android_webview/support_library/OWNERS
@@ -0,0 +1,4 @@
+gsennton@chromium.org
+ntfschr@chromium.org
+torne@chromium.org
+
diff --git a/ash/components/strings/ash_components_strings_ru.xtb b/ash/components/strings/ash_components_strings_ru.xtb
index 2aec05d3..e4449e1 100644
--- a/ash/components/strings/ash_components_strings_ru.xtb
+++ b/ash/components/strings/ash_components_strings_ru.xtb
@@ -3,6 +3,7 @@
 <translationbundle lang="ru">
 <translation id="104962181688258143">Открыть приложение "Файлы"</translation>
 <translation id="1126871238933253947">Переключиться на предыдущий язык ввода.</translation>
+<translation id="1134347825771908369">Отключить звук</translation>
 <translation id="1195667586424773550">Перетащить ссылку в адресную строку вкладки</translation>
 <translation id="1204450209689312104">Открыть новое окно в режиме инкогнито</translation>
 <translation id="1293699935367580298">Esc</translation>
@@ -55,6 +56,7 @@
 <translation id="353037708190149633">Сохранить все страницы, открытые в текущем окне, в закладках (в новой папке)</translation>
 <translation id="355103131818127604">Открыть ссылку в новой фоновой вкладке</translation>
 <translation id="3649256019230929621">Свернуть окно</translation>
+<translation id="3655154169297074232">Вкладки и окна</translation>
 <translation id="3668361878347172356">Повторить отмененное действие</translation>
 <translation id="3720939646656082033">Открыть ссылку в новой вкладке и переключиться на нее</translation>
 <translation id="3725795051337497754">Закрыть активную вкладку</translation>
@@ -70,6 +72,8 @@
 <translation id="4123108089450197101">Сохранить ссылку как закладку</translation>
 <translation id="4141203561740478845">Выделить ряд с адресной строкой</translation>
 <translation id="4148761611071495477"><ph name="CTRL" /><ph name="SEPARATOR" /><ph name="G" /> или <ph name="ENTER" /></translation>
+<translation id="4240486403425279990">Режим обзора</translation>
+<translation id="4472417192667361414">Настройки экрана и системы</translation>
 <translation id="4556221320735744018">Открыть страницу справки по быстрым клавишам</translation>
 <translation id="4628718545549558538">Открыть панель состояния (на которой расположено изображение профиля)</translation>
 <translation id="4642092649622328492">Сделать скриншот части экрана</translation>
@@ -134,6 +138,7 @@
 <translation id="8130528849632411619">Перейти к началу документа</translation>
 <translation id="8147954207400281792"><ph name="CTRL" /><ph name="SEPARATOR" /><ph name="K" /> или <ph name="E" /></translation>
 <translation id="8234414138295101081">Повернуть экран на 90 градусов</translation>
+<translation id="826184564253127735">Просмотр быстрых клавиш</translation>
 <translation id="836869401750819675">Открыть страницу "Скачанные файлы"</translation>
 <translation id="8388247778047144397">Перетащить ссылку в пустую область на панели вкладок</translation>
 <translation id="8389638407792712197">Открыть новое окно</translation>
@@ -146,5 +151,6 @@
 <translation id="8727232706774971183">Посмотреть уведомления</translation>
 <translation id="88986195241502842">На страницу вниз</translation>
 <translation id="8903921497873541725">Увеличить</translation>
+<translation id="9106898733795143799">Страница и браузер</translation>
 <translation id="9179672198516322668">Часто используемые быстрые клавиши</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ash/strings/ash_strings_am.xtb b/ash/strings/ash_strings_am.xtb
index c7eca93..d064a99 100644
--- a/ash/strings/ash_strings_am.xtb
+++ b/ash/strings/ash_strings_am.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">አነስተኛ ኃይል ያለው ባትሪ መሙያ</translation>
 <translation id="2135456203358955318">የተተከለ ማጉያ</translation>
 <translation id="2144487987174258011">Adobe Flash Playerን ለማዘመን ዳግም ያስጀምሩ</translation>
-<translation id="2191905770366256395">የእርስዎ ሊነቀል የሚችል የቁልፍ ሰሌድዳ በጣም ወሳኝ የሆነ ዝማኔ ያስፈልገዋል</translation>
 <translation id="2208323208084708176">የተዋሃደ የዴስክቶፕ ሁነታ</translation>
 <translation id="2220572644011485463">ፒን ወይም የይለፍ ቃል</translation>
 <translation id="225680501294068881">መሣሪያዎችን በመቃኘት ላይ...</translation>
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 501abcf..94390bc 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">شاحن منخفض الطاقة</translation>
 <translation id="2135456203358955318">المكبّر الذي تم إرساؤه</translation>
 <translation id="2144487987174258011">‏إعادة التشغيل لتحديث Adobe Flash Player</translation>
-<translation id="2191905770366256395">تحتاج لوحة المفاتيح القابلة للفصل إلى تحديث مهم.</translation>
 <translation id="2208323208084708176">وضع سطح المكتب الموحد</translation>
 <translation id="2220572644011485463">رقم التعريف الشخصي أو كلمة المرور</translation>
 <translation id="225680501294068881">جارٍ البحث عن أجهزة...</translation>
diff --git a/ash/strings/ash_strings_bg.xtb b/ash/strings/ash_strings_bg.xtb
index 687dbc4..1a44501 100644
--- a/ash/strings/ash_strings_bg.xtb
+++ b/ash/strings/ash_strings_bg.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Спиране на предаването на „<ph name="TAB_NAME" />“ към „<ph name="RECEIVER_NAME" />“</translation>
 <translation id="2127372758936585790">Зарядно устройство с малка мощност</translation>
 <translation id="2144487987174258011">Рестартирайте, за да актуализирате Adobe Flash Player</translation>
-<translation id="2191905770366256395">Вашата отделяща се клавиатура се нуждае от критична актуализация</translation>
 <translation id="2208323208084708176">Режим на обединен работен плот</translation>
 <translation id="2220572644011485463">ПИН код или парола</translation>
 <translation id="225680501294068881">Сканира се за устройства...</translation>
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index 29463802..0276344ad 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="TAB_NAME" /> কে <ph name="RECEIVER_NAME" /> এ কাস্ট করা বন্ধ করুন</translation>
 <translation id="2127372758936585790">নিম্ন শক্তির চার্জার</translation>
 <translation id="2144487987174258011">Adobe ফ্ল্যাশ প্লেয়ার আপডেট করার জন্য বন্ধ করে আবার চালু করুন</translation>
-<translation id="2191905770366256395">আলাদা করা যায় এমন কীবোর্ডের একটি জরুরি আপডেট প্রয়োজন</translation>
 <translation id="2208323208084708176">একীভূত ডেস্কটপ মোড</translation>
 <translation id="2220572644011485463">PIN বা পাসওয়ার্ড</translation>
 <translation id="225680501294068881">ডিভাইসগুলির জন্য স্ক্যান করা হচ্ছে...</translation>
diff --git a/ash/strings/ash_strings_ca.xtb b/ash/strings/ash_strings_ca.xtb
index 06ab28d0..d2ce401 100644
--- a/ash/strings/ash_strings_ca.xtb
+++ b/ash/strings/ash_strings_ca.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Deixa d'emetre <ph name="TAB_NAME" /> a <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Carregador de baix consum</translation>
 <translation id="2144487987174258011">Reinicia per actualitzar Adobe Flash Player</translation>
-<translation id="2191905770366256395">El teclat extraïble necessita una actualització important</translation>
 <translation id="2208323208084708176">Mode d'escriptori unificat</translation>
 <translation id="2220572644011485463">PIN o contrasenya</translation>
 <translation id="225680501294068881">S'estan cercant dispositius...</translation>
diff --git a/ash/strings/ash_strings_cs.xtb b/ash/strings/ash_strings_cs.xtb
index 946f60f..072f024 100644
--- a/ash/strings/ash_strings_cs.xtb
+++ b/ash/strings/ash_strings_cs.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Nabíječka má příliš nízký výkon</translation>
 <translation id="2135456203358955318">Zadokovaná lupa</translation>
 <translation id="2144487987174258011">Aktualizace přehrávače Adobe Flash Player vyžaduje restart</translation>
-<translation id="2191905770366256395">Odpojitelná klávesnice vyžaduje kritickou aktualizaci</translation>
 <translation id="2208323208084708176">Jednotný režim klasické plochy</translation>
 <translation id="2220572644011485463">PIN nebo heslo</translation>
 <translation id="225680501294068881">Vyhledávání zařízení…</translation>
diff --git a/ash/strings/ash_strings_da.xtb b/ash/strings/ash_strings_da.xtb
index 6b011ae2..1b2725c 100644
--- a/ash/strings/ash_strings_da.xtb
+++ b/ash/strings/ash_strings_da.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Stop med at caste <ph name="TAB_NAME" /> til <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Oplader ved lav kraft</translation>
 <translation id="2144487987174258011">Genstart for at opdatere Adobe Flash Player</translation>
-<translation id="2191905770366256395">Dit aftagelige tastatur kræver en vigtig opdatering</translation>
 <translation id="2208323208084708176">Samlet skrivebordstilstand</translation>
 <translation id="2220572644011485463">Pin- eller adgangskode</translation>
 <translation id="225680501294068881">Søger efter enheder...</translation>
diff --git a/ash/strings/ash_strings_de.xtb b/ash/strings/ash_strings_de.xtb
index a618fd6..60bbab4 100644
--- a/ash/strings/ash_strings_de.xtb
+++ b/ash/strings/ash_strings_de.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Streamen von <ph name="TAB_NAME" /> an <ph name="RECEIVER_NAME" /> beenden</translation>
 <translation id="2127372758936585790">Schwachstrom-Ladegerät</translation>
 <translation id="2144487987174258011">Neu starten, um den Adobe Flash Player zu aktualisieren</translation>
-<translation id="2191905770366256395">Wichtiges Update für Ihre abnehmbare Tastatur</translation>
 <translation id="2208323208084708176">Unified Desktop-Modus</translation>
 <translation id="2220572644011485463">PIN oder Passwort</translation>
 <translation id="225680501294068881">Nach Geräten wird gesucht...</translation>
diff --git a/ash/strings/ash_strings_el.xtb b/ash/strings/ash_strings_el.xtb
index e15583a..e3700c4 100644
--- a/ash/strings/ash_strings_el.xtb
+++ b/ash/strings/ash_strings_el.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Χαμηλή ισχύς φορτιστή</translation>
 <translation id="2135456203358955318">Μεγεθυντικός φακός σε παράθυρο</translation>
 <translation id="2144487987174258011">Κάντε επανεκκίνηση για να ενημερώσετε το Adobe Flash Player</translation>
-<translation id="2191905770366256395">Απαιτείται σημαντική ενημέρωση του αποσπώμενου πληκτρολογίου σας</translation>
 <translation id="2208323208084708176">Ενιαία λειτουργία επιφάνειας εργασίας.</translation>
 <translation id="2220572644011485463">PIN ή κωδικός πρόσβασης</translation>
 <translation id="225680501294068881">Σάρωση για συσκευές…</translation>
diff --git a/ash/strings/ash_strings_en-GB.xtb b/ash/strings/ash_strings_en-GB.xtb
index ddfe6f7e..b221c54 100644
--- a/ash/strings/ash_strings_en-GB.xtb
+++ b/ash/strings/ash_strings_en-GB.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Low-power charger</translation>
 <translation id="2135456203358955318">Docked magnifier</translation>
 <translation id="2144487987174258011">Restart to update Adobe Flash Player</translation>
-<translation id="2191905770366256395">Your detachable keybaord needs a critical update</translation>
 <translation id="2208323208084708176">Unified desktop mode</translation>
 <translation id="2220572644011485463">PIN or password</translation>
 <translation id="225680501294068881">Scanning for devices...</translation>
diff --git a/ash/strings/ash_strings_es-419.xtb b/ash/strings/ash_strings_es-419.xtb
index 1eb0364..fbfaf5f 100644
--- a/ash/strings/ash_strings_es-419.xtb
+++ b/ash/strings/ash_strings_es-419.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Detener la transmisión de <ph name="TAB_NAME" /> a <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Carga lenta</translation>
 <translation id="2144487987174258011">Reinicia para actualizar Adobe Flash Player</translation>
-<translation id="2191905770366256395">Tu teclado desmontable necesita una actualización crítica</translation>
 <translation id="2208323208084708176">Modo de escritorio unificado</translation>
 <translation id="2220572644011485463">PIN o contraseña</translation>
 <translation id="225680501294068881">Buscando dispositivos...</translation>
diff --git a/ash/strings/ash_strings_es.xtb b/ash/strings/ash_strings_es.xtb
index 39de56e19..a5d63a7 100644
--- a/ash/strings/ash_strings_es.xtb
+++ b/ash/strings/ash_strings_es.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Dejar de enviar el contenido de la pestaña <ph name="TAB_NAME" /> a <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Carga lenta</translation>
 <translation id="2144487987174258011">Reinicia para actualizar Adobe Flash Player</translation>
-<translation id="2191905770366256395">Tu teclado independiente necesita una actualización crítica</translation>
 <translation id="2208323208084708176">Modo de escritorio unificado</translation>
 <translation id="2220572644011485463">PIN o contraseña</translation>
 <translation id="225680501294068881">Buscando dispositivos...</translation>
diff --git a/ash/strings/ash_strings_et.xtb b/ash/strings/ash_strings_et.xtb
index ffced2d..6393e8fe 100644
--- a/ash/strings/ash_strings_et.xtb
+++ b/ash/strings/ash_strings_et.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Peata vahekaardi <ph name="TAB_NAME" /> ülekandmine vastuvõtjasse <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Väikese energiakuluga laadija</translation>
 <translation id="2144487987174258011">Taaskäivitage Adobe Flash Playeri värskendamiseks</translation>
-<translation id="2191905770366256395">Eemaldatav klaviatuur vajab kriitilist värskendust</translation>
 <translation id="2208323208084708176">Ühendatud töölaua režiim</translation>
 <translation id="2220572644011485463">PIN-kood või parool</translation>
 <translation id="225680501294068881">Seadmete skannimine ...</translation>
diff --git a/ash/strings/ash_strings_fa.xtb b/ash/strings/ash_strings_fa.xtb
index 7afd73f..2d9d89b 100644
--- a/ash/strings/ash_strings_fa.xtb
+++ b/ash/strings/ash_strings_fa.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">شارژر برق ضعیف</translation>
 <translation id="2135456203358955318">ذره‌بین متصل</translation>
 <translation id="2144487987174258011">‏برای به‌روزرسانی Adobe Flash Player، راه‌اندازی مجدد کنید</translation>
-<translation id="2191905770366256395">لازم است صفحه‌کلید قابل جدا شدن به‌روزرسانی ضروری شود</translation>
 <translation id="2208323208084708176">حالت میزکار یکپارچه</translation>
 <translation id="2220572644011485463">پین یا گذرواژه</translation>
 <translation id="225680501294068881">درحال جستجو برای دستگاه‌ها...</translation>
diff --git a/ash/strings/ash_strings_fi.xtb b/ash/strings/ash_strings_fi.xtb
index ad26faad..f16443b 100644
--- a/ash/strings/ash_strings_fi.xtb
+++ b/ash/strings/ash_strings_fi.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Lopeta suoratoisto: <ph name="TAB_NAME" />, <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Pienitehoinen laturi</translation>
 <translation id="2144487987174258011">Päivitä Adobe Flash Player käynnistämällä uudelleen.</translation>
-<translation id="2191905770366256395">Irrotettavaan näppäimistöösi täytyy asentaa kriittinen päivitys</translation>
 <translation id="2208323208084708176">Yhtenäisen työpöydän tila</translation>
 <translation id="2220572644011485463">PIN-koodi tai salasana</translation>
 <translation id="225680501294068881">Etsitään laitteita...</translation>
diff --git a/ash/strings/ash_strings_fil.xtb b/ash/strings/ash_strings_fil.xtb
index 42fa8661..d38f56bb 100644
--- a/ash/strings/ash_strings_fil.xtb
+++ b/ash/strings/ash_strings_fil.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Ihinto ang pag-cast ng <ph name="TAB_NAME" /> sa <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Low-power charger</translation>
 <translation id="2144487987174258011">I-restart upang i-update ang Adobe Flash Player</translation>
-<translation id="2191905770366256395">Nangangailangan ng mahalagang update ang iyong naaalis na keyboard</translation>
 <translation id="2208323208084708176">Unified desktop mode</translation>
 <translation id="2220572644011485463">PIN o password</translation>
 <translation id="225680501294068881">Nag-i-scan para sa mga device...</translation>
diff --git a/ash/strings/ash_strings_fr.xtb b/ash/strings/ash_strings_fr.xtb
index 73a121f..c8a1fe2 100644
--- a/ash/strings/ash_strings_fr.xtb
+++ b/ash/strings/ash_strings_fr.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Arrêter de diffuser <ph name="TAB_NAME" /> sur "<ph name="RECEIVER_NAME" />"</translation>
 <translation id="2127372758936585790">Chargeur de faible puissance</translation>
 <translation id="2144487987174258011">Redémarrez pour mettre Adobe Flash Player à jour</translation>
-<translation id="2191905770366256395">Votre clavier amovible nécessite une mise à jour critique</translation>
 <translation id="2208323208084708176">Mode bureau unifié</translation>
 <translation id="2220572644011485463">Code ou mot de passe</translation>
 <translation id="225680501294068881">Recherche d'appareils…</translation>
diff --git a/ash/strings/ash_strings_gu.xtb b/ash/strings/ash_strings_gu.xtb
index ad5528c..1fd1209 100644
--- a/ash/strings/ash_strings_gu.xtb
+++ b/ash/strings/ash_strings_gu.xtb
@@ -23,6 +23,7 @@
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">લૉન્ચર</translation>
 <translation id="1525508553941733066">છોડી દો</translation>
+<translation id="1537254971476575106">પૂર્ણસ્ક્રીન બૃહદદર્શક</translation>
 <translation id="15373452373711364">મોટું માઉસ કર્સર</translation>
 <translation id="1550523713251050646">વધુ વિકલ્પો માટે ક્લિક કરો</translation>
 <translation id="1567387640189251553">તમે છેલ્લે પાસવર્ડ દાખલ કર્યો, ત્યાર પછી એક અલગ કીબોર્ડ કનેક્ટ કરવામાં આવ્યું છે. તે તમારા કીસ્ટ્રોકની ચોરી કરવાનો પ્રયાસ કરતું હોઈ શકે છે.</translation>
@@ -51,10 +52,11 @@
 <translation id="2049639323467105390">આ ઉપકરણને <ph name="DOMAIN" /> દ્વારા મેનેજ કરવામાં આવેલું છે.</translation>
 <translation id="2050339315714019657">પોર્ટ્રેટ</translation>
 <translation id="2067602449040652523">કીબોર્ડનું તેજ</translation>
+<translation id="2081529251031312395">$1 હજુ થોડા સમય પછી સાઇન ઇન કરી શકશે.</translation>
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" /> પર <ph name="TAB_NAME" /> ને કાસ્ટ કરવાનું રોકો</translation>
 <translation id="2127372758936585790">નિમ્ન-પાવર ચાર્જર</translation>
+<translation id="2135456203358955318">ડૉક કરેલ બૃહદદર્શક</translation>
 <translation id="2144487987174258011">Adobe Flash Player અપડેટ કરવા પુનઃપ્રારંભ કરો</translation>
-<translation id="2191905770366256395">અલગ પાડી શકાય તેવા તમારા કીબોર્ડ માટે મહત્ત્વપૂર્ણ અપડેટ જરૂરી છે</translation>
 <translation id="2208323208084708176">એકીકૃત ડેસ્કટૉપ મોડ</translation>
 <translation id="2220572644011485463">PIN અથવા પાસવર્ડ</translation>
 <translation id="225680501294068881">ઉપકરણો માટે સ્કેન કરી રહ્યું છે...</translation>
diff --git a/ash/strings/ash_strings_hi.xtb b/ash/strings/ash_strings_hi.xtb
index 577e64a..36108226 100644
--- a/ash/strings/ash_strings_hi.xtb
+++ b/ash/strings/ash_strings_hi.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" /> को <ph name="TAB_NAME" /> कास्ट करना बंद करें</translation>
 <translation id="2127372758936585790">कम-शक्ति वाला चार्जर</translation>
 <translation id="2144487987174258011">Adobe Flash Player को अपडेट करने के लिए फिर से चालू करें</translation>
-<translation id="2191905770366256395">आपके अलग किए जाने लायक कीबोर्ड में एक महत्वपूर्ण अपडेट ज़रूरी है</translation>
 <translation id="2208323208084708176">संयुक्त डेस्कटॉप मोड</translation>
 <translation id="2220572644011485463">पिन या पासवर्ड</translation>
 <translation id="225680501294068881">डिवाइस स्कैन किए जा रहे हैं...</translation>
diff --git a/ash/strings/ash_strings_hr.xtb b/ash/strings/ash_strings_hr.xtb
index efaa552..72c08d1 100644
--- a/ash/strings/ash_strings_hr.xtb
+++ b/ash/strings/ash_strings_hr.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Punjač male snage</translation>
 <translation id="2135456203358955318">Usidreno povećalo</translation>
 <translation id="2144487987174258011">Ponovno pokrenite da biste ažurirali Adobe Flash Player</translation>
-<translation id="2191905770366256395">Potrebno je kritično ažuriranje za vašu odvojivu tipkovnicu</translation>
 <translation id="2208323208084708176">Način jedinstvene radne površine</translation>
 <translation id="2220572644011485463">PIN ili zaporka</translation>
 <translation id="225680501294068881">Pretraživanje uređaja...</translation>
diff --git a/ash/strings/ash_strings_hu.xtb b/ash/strings/ash_strings_hu.xtb
index 6ab4962..7a5d697e 100644
--- a/ash/strings/ash_strings_hu.xtb
+++ b/ash/strings/ash_strings_hu.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">„<ph name="TAB_NAME" />” lap „<ph name="RECEIVER_NAME" />” eszközre történő átküldésének leállítása</translation>
 <translation id="2127372758936585790">Kis teljesítményű töltő</translation>
 <translation id="2144487987174258011">Az Adobe Flash Player frissítéséhez újraindítás szükséges</translation>
-<translation id="2191905770366256395">Szükség van a leválasztható billentyűzet kritikus frissítésének telepítésére</translation>
 <translation id="2208323208084708176">Egységes asztali mód</translation>
 <translation id="2220572644011485463">PIN-kód vagy jelszó</translation>
 <translation id="225680501294068881">Eszközök keresése...</translation>
diff --git a/ash/strings/ash_strings_id.xtb b/ash/strings/ash_strings_id.xtb
index 7ea1f10..b62f227 100644
--- a/ash/strings/ash_strings_id.xtb
+++ b/ash/strings/ash_strings_id.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Pengisi daya rendah</translation>
 <translation id="2135456203358955318">Kaca pembesar yang dipasang ke dok</translation>
 <translation id="2144487987174258011">Nyalakan ulang untuk mengupdate Adobe Flash Player</translation>
-<translation id="2191905770366256395">Keyboard yang dapat dilepas memerlukan update penting</translation>
 <translation id="2208323208084708176">Mode desktop terpadu</translation>
 <translation id="2220572644011485463">PIN atau sandi</translation>
 <translation id="225680501294068881">Memindai perangkat...</translation>
diff --git a/ash/strings/ash_strings_it.xtb b/ash/strings/ash_strings_it.xtb
index f4c2006..d56cfab 100644
--- a/ash/strings/ash_strings_it.xtb
+++ b/ash/strings/ash_strings_it.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Interrompi la trasmissione di <ph name="TAB_NAME" /> su <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Caricabatterie a basso consumo</translation>
 <translation id="2144487987174258011">Riavvia per aggiornare Adobe Flash Player</translation>
-<translation id="2191905770366256395">La tastiera rimovibile richiede un aggiornamento critico</translation>
 <translation id="2208323208084708176">Modalità desktop unificato</translation>
 <translation id="2220572644011485463">PIN o password</translation>
 <translation id="225680501294068881">Ricerca dispositivi in corso...</translation>
diff --git a/ash/strings/ash_strings_iw.xtb b/ash/strings/ash_strings_iw.xtb
index 486f0f52..517e480 100644
--- a/ash/strings/ash_strings_iw.xtb
+++ b/ash/strings/ash_strings_iw.xtb
@@ -23,6 +23,7 @@
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">מפעיל</translation>
 <translation id="1525508553941733066">סגור</translation>
+<translation id="1537254971476575106">מגדיל מסך מלא</translation>
 <translation id="15373452373711364">סמן עכבר גדול</translation>
 <translation id="1550523713251050646">לחץ לקבלת אפשרויות נוספות</translation>
 <translation id="1567387640189251553">חוברה מקלדת אחרת מאז שהזנת את הסיסמה בפעם האחרונה. ייתכן שהיא מנסה לתעד את ההקשות שלך.</translation>
@@ -51,10 +52,11 @@
 <translation id="2049639323467105390">מכשיר זה מנוהל על ידי <ph name="DOMAIN" />.</translation>
 <translation id="2050339315714019657">לאורך</translation>
 <translation id="2067602449040652523">בהירות מקלדת</translation>
+<translation id="2081529251031312395">ל-$1 עדיין תהיה אפשרות להיכנס מאוחר יותר.</translation>
 <translation id="2122028596993374965">הפסק להעביר את <ph name="TAB_NAME" /> אל <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">מטען בעל מתח נמוך</translation>
+<translation id="2135456203358955318">מגדיל במצב מעוגן</translation>
 <translation id="2144487987174258011">‏הפעל מחדש כדי לעדכן את Adobe Flash Player</translation>
-<translation id="2191905770366256395">המקלדת הניתנת לניתוק זקוקה לעדכון קריטי</translation>
 <translation id="2208323208084708176">מצב שולחן עבודה מאוחד</translation>
 <translation id="2220572644011485463">‏PIN או סיסמה</translation>
 <translation id="225680501294068881">סורק לאיתור מכשירים...</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index 68bf1fc..c437df18 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" /> への <ph name="TAB_NAME" /> のキャストを停止する</translation>
 <translation id="2127372758936585790">低電力の充電器</translation>
 <translation id="2144487987174258011">Adobe Flash Player を更新するには再起動してください</translation>
-<translation id="2191905770366256395">お使いのキーボード(取り外し可能)に重要なアップデートを適用する必要があります</translation>
 <translation id="2208323208084708176">デスクトップ統合モード</translation>
 <translation id="2220572644011485463">PIN またはパスワード</translation>
 <translation id="225680501294068881">デバイスをスキャンしています...</translation>
diff --git a/ash/strings/ash_strings_kn.xtb b/ash/strings/ash_strings_kn.xtb
index 6b0b07c..2f1c960 100644
--- a/ash/strings/ash_strings_kn.xtb
+++ b/ash/strings/ash_strings_kn.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="TAB_NAME" /> ಅನ್ನು <ph name="RECEIVER_NAME" /> ಗೆ ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ</translation>
 <translation id="2127372758936585790">ಕಡಿಮೆ ವಿದ್ಯುತ್ ಚಾರ್ಜರ್</translation>
 <translation id="2144487987174258011">Adobe Flash Player ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
-<translation id="2191905770366256395">ನಿಮ್ಮ ಪ್ರತ್ಯೇಕಿಸಬಹುದಾದ ಕೀಬೋರ್ಡ್‌ಗೆ ವಿಷಮಸ್ಥಿತಿ ಅಪ್‌ಡೇಟ್‌ನ ಅಗತ್ಯವಿದೆ</translation>
 <translation id="2208323208084708176">ಏಕೀಕೃತ ಡೆಸ್ಕ್‌ಟಾಪ್ ಮೋಡ್</translation>
 <translation id="2220572644011485463">ಪಿನ್ ಅಥವಾ ಪಾಸ್‌ವರ್ಡ್</translation>
 <translation id="225680501294068881">ಸಾಧನಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತಿದೆ...</translation>
diff --git a/ash/strings/ash_strings_ko.xtb b/ash/strings/ash_strings_ko.xtb
index 62510fe..4b88d909 100644
--- a/ash/strings/ash_strings_ko.xtb
+++ b/ash/strings/ash_strings_ko.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" />에 <ph name="TAB_NAME" /> 전송 중지</translation>
 <translation id="2127372758936585790">저출력 충전기</translation>
 <translation id="2144487987174258011">Adobe Flash Player를 업데이트하려면 다시 시작하세요.</translation>
-<translation id="2191905770366256395">분리식 키보드에 중요 업데이트 필요</translation>
 <translation id="2208323208084708176">통합 바탕화면 모드</translation>
 <translation id="2220572644011485463">PIN 또는 비밀번호</translation>
 <translation id="225680501294068881">기기 검색 중...</translation>
diff --git a/ash/strings/ash_strings_lt.xtb b/ash/strings/ash_strings_lt.xtb
index 6815879..8377837 100644
--- a/ash/strings/ash_strings_lt.xtb
+++ b/ash/strings/ash_strings_lt.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Mažos galios įkroviklis</translation>
 <translation id="2135456203358955318">Prie doko prijungtas didintuvas</translation>
 <translation id="2144487987174258011">Paleiskite iš naujo, kad atnaujintumėte „Adobe Flash Player“</translation>
-<translation id="2191905770366256395">Atjungiamą klaviatūrą būtina atnaujinti</translation>
 <translation id="2208323208084708176">Vieno darbalaukio režimas</translation>
 <translation id="2220572644011485463">PIN kodas arba slaptažodis</translation>
 <translation id="225680501294068881">Ieškoma įrenginių...</translation>
diff --git a/ash/strings/ash_strings_lv.xtb b/ash/strings/ash_strings_lv.xtb
index 9bd8fd68b..b443ddd 100644
--- a/ash/strings/ash_strings_lv.xtb
+++ b/ash/strings/ash_strings_lv.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Apturēt “<ph name="TAB_NAME" />” apraidi uztvērējā “<ph name="RECEIVER_NAME" />”</translation>
 <translation id="2127372758936585790">Lādētājs ar mazu strāvas padevi</translation>
 <translation id="2144487987174258011">Restartējiet, lai atjauninātu Adobe Flash Player</translation>
-<translation id="2191905770366256395">Jūsu noņemamajai tastatūrai nepieciešams svarīgs atjauninājums</translation>
 <translation id="2208323208084708176">Vienots darbvirsmas režīms</translation>
 <translation id="2220572644011485463">PIN vai parole</translation>
 <translation id="225680501294068881">Notiek ierīču meklēšana...</translation>
diff --git a/ash/strings/ash_strings_ml.xtb b/ash/strings/ash_strings_ml.xtb
index edc74112..bdd3891 100644
--- a/ash/strings/ash_strings_ml.xtb
+++ b/ash/strings/ash_strings_ml.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="TAB_NAME" />, <ph name="RECEIVER_NAME" /> എന്നതിലേക്ക് കാസ്‌റ്റുചെയ്യുന്നത് നിർത്തുക</translation>
 <translation id="2127372758936585790">കുറഞ്ഞ തോതിൽ വൈദ്യുതി പ്രവഹിക്കുന്ന ചാർജർ</translation>
 <translation id="2144487987174258011">Adobe Flash Player അപ്‌ഡേറ്റുചെയ്യാൻ പുനരാരംഭിക്കുക</translation>
-<translation id="2191905770366256395">നിങ്ങളുടെ വേർപെടുത്താനാകുന്ന കീബോഡിന് നിർണ്ണായക അപ്‌ഡേറ്റ് ആവശ്യമാണ്</translation>
 <translation id="2208323208084708176">ഏകീകൃത ഡെസ്‌ക്‌ടോപ്പ് മോഡ്</translation>
 <translation id="2220572644011485463">പിൻ അല്ലെങ്കിൽ പാസ്‌വേഡ്</translation>
 <translation id="225680501294068881">ഉപകരണങ്ങൾക്കായി സ്‌കാൻ ചെയ്യുന്നു...</translation>
diff --git a/ash/strings/ash_strings_mr.xtb b/ash/strings/ash_strings_mr.xtb
index 0913266..3ffdbd6 100644
--- a/ash/strings/ash_strings_mr.xtb
+++ b/ash/strings/ash_strings_mr.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" /> वर <ph name="TAB_NAME" /> कास्ट करणे थांबवा</translation>
 <translation id="2127372758936585790">निम्न-उर्जेचे चार्जर</translation>
 <translation id="2144487987174258011">Adobe Flash Player अपडेट करण्यासाठी पुन्हा सुरू करा</translation>
-<translation id="2191905770366256395">तुमच्या वेगळ्या करण्यायोग्य कीबोर्डला एका गंभीर अपडेटची आवश्यकता आहे</translation>
 <translation id="2208323208084708176">एकीकृत डेस्कटॉप मोड</translation>
 <translation id="2220572644011485463">पिन किंवा पासवर्ड</translation>
 <translation id="225680501294068881">डिव्हाइसेससाठी स्कॅन करत आहे...</translation>
diff --git a/ash/strings/ash_strings_ms.xtb b/ash/strings/ash_strings_ms.xtb
index 5ca6a57..2092b930 100644
--- a/ash/strings/ash_strings_ms.xtb
+++ b/ash/strings/ash_strings_ms.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Pengecas berkuasa rendah</translation>
 <translation id="2135456203358955318">Penggadang didok</translation>
 <translation id="2144487987174258011">Mulakan semula untuk mengemas kini Pemain Adobe Flash</translation>
-<translation id="2191905770366256395">Papan kekunci anda yang boleh dicabut memerlukan kemas kini kritikal</translation>
 <translation id="2208323208084708176">Mod desktop bersatu</translation>
 <translation id="2220572644011485463">PIN atau kata laluan</translation>
 <translation id="225680501294068881">Mengimbas untuk peranti...</translation>
diff --git a/ash/strings/ash_strings_nl.xtb b/ash/strings/ash_strings_nl.xtb
index aa6a6fe..ff06ef8f 100644
--- a/ash/strings/ash_strings_nl.xtb
+++ b/ash/strings/ash_strings_nl.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Casten van <ph name="TAB_NAME" /> naar <ph name="RECEIVER_NAME" /> stopzetten</translation>
 <translation id="2127372758936585790">Laag-vermogen-lader</translation>
 <translation id="2144487987174258011">Start opnieuw op om Adobe Flash Player te updaten</translation>
-<translation id="2191905770366256395">Je afneembare toetsenbord heeft een essentiële update nodig</translation>
 <translation id="2208323208084708176">Samengestelde desktopmodus</translation>
 <translation id="2220572644011485463">Pincode of wachtwoord</translation>
 <translation id="225680501294068881">Zoeken naar apparaten...</translation>
diff --git a/ash/strings/ash_strings_no.xtb b/ash/strings/ash_strings_no.xtb
index 74ff0364..dac09cd 100644
--- a/ash/strings/ash_strings_no.xtb
+++ b/ash/strings/ash_strings_no.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Slutt å caste <ph name="TAB_NAME" /> til <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Lading med lav effekt</translation>
 <translation id="2144487987174258011">Start på nytt for å oppdatere Adobe Flash Player</translation>
-<translation id="2191905770366256395">Det avtakbare tastaturet trenger en kritisk oppdatering</translation>
 <translation id="2208323208084708176">Enhetlig skrivebordsmodus</translation>
 <translation id="2220572644011485463">PIN-kode eller passord</translation>
 <translation id="225680501294068881">Leter etter enheter ...</translation>
diff --git a/ash/strings/ash_strings_pl.xtb b/ash/strings/ash_strings_pl.xtb
index 9e3cc14..379c7fef 100644
--- a/ash/strings/ash_strings_pl.xtb
+++ b/ash/strings/ash_strings_pl.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Zakończ przesyłanie karty <ph name="TAB_NAME" /> do: <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Ładowarka o małej mocy</translation>
 <translation id="2144487987174258011">Uruchom ponownie, by zaktualizować Adobe Flash Playera</translation>
-<translation id="2191905770366256395">Odłączana klawiatura wymaga krytycznej aktualizacji.</translation>
 <translation id="2208323208084708176">Tryb ujednoliconego pulpitu</translation>
 <translation id="2220572644011485463">Kod PIN lub hasło</translation>
 <translation id="225680501294068881">Skanowanie w poszukiwaniu urządzeń...</translation>
diff --git a/ash/strings/ash_strings_pt-BR.xtb b/ash/strings/ash_strings_pt-BR.xtb
index 379d77e..2a24c9d 100644
--- a/ash/strings/ash_strings_pt-BR.xtb
+++ b/ash/strings/ash_strings_pt-BR.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Carregador de baixa potência</translation>
 <translation id="2135456203358955318">Lupa ancorada</translation>
 <translation id="2144487987174258011">Reinicie para atualizar o Adobe Flash Player</translation>
-<translation id="2191905770366256395">Seu teclado removível precisa de uma atualização crítica</translation>
 <translation id="2208323208084708176">Modo de área de trabalho unificada.</translation>
 <translation id="2220572644011485463">PIN ou senha</translation>
 <translation id="225680501294068881">Procurando dispositivos...</translation>
diff --git a/ash/strings/ash_strings_pt-PT.xtb b/ash/strings/ash_strings_pt-PT.xtb
index d1d57141..c2f1f6c 100644
--- a/ash/strings/ash_strings_pt-PT.xtb
+++ b/ash/strings/ash_strings_pt-PT.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Parar a transmissão de <ph name="TAB_NAME" /> para <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Carregador de baixo consumo</translation>
 <translation id="2144487987174258011">Reinicie para atualizar o Adobe Flash Player</translation>
-<translation id="2191905770366256395">O teclado amovível necessita de uma atualização crítica</translation>
 <translation id="2208323208084708176">Modo de ambiente de trabalho unificado</translation>
 <translation id="2220572644011485463">PIN ou palavra-passe</translation>
 <translation id="225680501294068881">A procurar dispositivos...</translation>
diff --git a/ash/strings/ash_strings_ro.xtb b/ash/strings/ash_strings_ro.xtb
index 8be6c54..5d8b4e8f 100644
--- a/ash/strings/ash_strings_ro.xtb
+++ b/ash/strings/ash_strings_ro.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Încărcător de putere joasă</translation>
 <translation id="2135456203358955318">Lupă andocată</translation>
 <translation id="2144487987174258011">Repornește ca să actualizezi Adobe Flash Player</translation>
-<translation id="2191905770366256395">Tastatura detașabilă are nevoie de o actualizare esențială</translation>
 <translation id="2208323208084708176">Modul Desktop unificat</translation>
 <translation id="2220572644011485463">PIN sau parolă</translation>
 <translation id="225680501294068881">Se caută gadgeturi...</translation>
diff --git a/ash/strings/ash_strings_ru.xtb b/ash/strings/ash_strings_ru.xtb
index 86adf479..736a6af6 100644
--- a/ash/strings/ash_strings_ru.xtb
+++ b/ash/strings/ash_strings_ru.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Остановить трансляцию вкладки "<ph name="TAB_NAME" />" на устройство "<ph name="RECEIVER_NAME" />"</translation>
 <translation id="2127372758936585790">Маломощное зарядное устройство</translation>
 <translation id="2144487987174258011">Перезагрузите, чтобы обновить Adobe Flash Player</translation>
-<translation id="2191905770366256395">Необходимо обновить внешнюю клавиатуру</translation>
 <translation id="2208323208084708176">Единый рабочий стол</translation>
 <translation id="2220572644011485463">PIN-код или пароль</translation>
 <translation id="225680501294068881">Поиск устройств…</translation>
diff --git a/ash/strings/ash_strings_sk.xtb b/ash/strings/ash_strings_sk.xtb
index e548bba..585211b6 100644
--- a/ash/strings/ash_strings_sk.xtb
+++ b/ash/strings/ash_strings_sk.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Nabíjačka s nízkym výkonom</translation>
 <translation id="2135456203358955318">Ukotvená lupa</translation>
 <translation id="2144487987174258011">Reštartujte a aktualizujte tak Adobe Flash Player</translation>
-<translation id="2191905770366256395">Odoberateľná klávesnica potrebuje závažnú aktualizáciu</translation>
 <translation id="2208323208084708176">Režim zjednotenej pracovnej plochy</translation>
 <translation id="2220572644011485463">PIN alebo heslo</translation>
 <translation id="225680501294068881">Hľadajú sa zariadenia...</translation>
diff --git a/ash/strings/ash_strings_sl.xtb b/ash/strings/ash_strings_sl.xtb
index 002a2be..da530219 100644
--- a/ash/strings/ash_strings_sl.xtb
+++ b/ash/strings/ash_strings_sl.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Nizkoenergijski polnilnik</translation>
 <translation id="2135456203358955318">Zasidrana lupa</translation>
 <translation id="2144487987174258011">Če želite posodobiti Adobe Flash Player, znova zaženite</translation>
-<translation id="2191905770366256395">Snemljiva tipkovnica potrebuje nujno posodobitev</translation>
 <translation id="2208323208084708176">Način enotnega namizja</translation>
 <translation id="2220572644011485463">Koda PIN ali geslo</translation>
 <translation id="225680501294068881">Iskanje naprav ...</translation>
diff --git a/ash/strings/ash_strings_sr.xtb b/ash/strings/ash_strings_sr.xtb
index a67493a4..449203d 100644
--- a/ash/strings/ash_strings_sr.xtb
+++ b/ash/strings/ash_strings_sr.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Пуњач мале снаге</translation>
 <translation id="2135456203358955318">Монтирана лупа екрана</translation>
 <translation id="2144487987174258011">Покрените поново да бисте ажурирали Adobe Flash Player</translation>
-<translation id="2191905770366256395">Треба да инсталирате важно ажурирање одвојиве тастатуре</translation>
 <translation id="2208323208084708176">Режим спојених радних површина</translation>
 <translation id="2220572644011485463">PIN или лозинка</translation>
 <translation id="225680501294068881">Скенирање уређаја...</translation>
diff --git a/ash/strings/ash_strings_sv.xtb b/ash/strings/ash_strings_sv.xtb
index 95200d5..014105b 100644
--- a/ash/strings/ash_strings_sv.xtb
+++ b/ash/strings/ash_strings_sv.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Laddning med låg effekt</translation>
 <translation id="2135456203358955318">Dockad skärmförstorare</translation>
 <translation id="2144487987174258011">Starta om för att uppdatera Adobe Flash Player</translation>
-<translation id="2191905770366256395">Det behövs en viktig uppdatering till ditt frånkopplingsbara tangentbord</translation>
 <translation id="2208323208084708176">Enhetligt skrivbordsläge</translation>
 <translation id="2220572644011485463">Pinkod eller lösenord</translation>
 <translation id="225680501294068881">Söker efter enheter ...</translation>
diff --git a/ash/strings/ash_strings_sw.xtb b/ash/strings/ash_strings_sw.xtb
index 2e74d4e8..ff2e5bd 100644
--- a/ash/strings/ash_strings_sw.xtb
+++ b/ash/strings/ash_strings_sw.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Chaja ya nguvu ya chini</translation>
 <translation id="2135456203358955318">Kikuzaji kilichofungwa</translation>
 <translation id="2144487987174258011">Zima kisha uwashe ili usasishe Adobe Flash Player</translation>
-<translation id="2191905770366256395">Kibodi unayoweza kutenganisha inahitaji sasisho muhimu</translation>
 <translation id="2208323208084708176">Hali ya eneo-kazi iliyounganishwa</translation>
 <translation id="2220572644011485463">PIN au nenosiri</translation>
 <translation id="225680501294068881">Inatambazaa vifaa...</translation>
diff --git a/ash/strings/ash_strings_ta.xtb b/ash/strings/ash_strings_ta.xtb
index 6bf1982..fcd36d8 100644
--- a/ash/strings/ash_strings_ta.xtb
+++ b/ash/strings/ash_strings_ta.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="TAB_NAME" />ஐ <ph name="RECEIVER_NAME" />க்கு அனுப்புவதை நிறுத்து</translation>
 <translation id="2127372758936585790">குறைந்த சக்திகொண்ட சார்ஜர்</translation>
 <translation id="2144487987174258011">Adobe Flash Playerஐப் புதுப்பிக்க, மீண்டும் தொடங்கவும்</translation>
-<translation id="2191905770366256395">அகற்றத்தக்க விசைப்பலகைக்கு முக்கியப் புதுப்பிப்பு வேண்டும்</translation>
 <translation id="2208323208084708176">ஒன்றிணைந்த டெஸ்க்டாப் பயன்முறை</translation>
 <translation id="2220572644011485463">பின் அல்லது கடவுச்சொல்</translation>
 <translation id="225680501294068881">சாதனங்களைக் கண்டறிகிறது...</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index 8f7d7b7cb..242e239 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="RECEIVER_NAME" />కి <ph name="TAB_NAME" />ని ప్రసారం చేయడాన్ని ఆపివేయి</translation>
 <translation id="2127372758936585790">తక్కువ-పవర్ గల ఛార్జర్</translation>
 <translation id="2144487987174258011">Adobe Flash Playerని నవీకరించడానికి పున:ప్రారంభించండి</translation>
-<translation id="2191905770366256395">మీ తీసివేయగల కీబోర్డ్‌కి ఒక ముఖ్యమైన అప్‌డేట్ అవసరం</translation>
 <translation id="2208323208084708176">ఏకీకృత డెస్క్‌టాప్ మోడ్</translation>
 <translation id="2220572644011485463">PIN లేదా పాస్‌వర్డ్</translation>
 <translation id="225680501294068881">పరికరాల కోసం స్కాన్ చేస్తోంది...</translation>
diff --git a/ash/strings/ash_strings_th.xtb b/ash/strings/ash_strings_th.xtb
index 963936cc..2f5d944 100644
--- a/ash/strings/ash_strings_th.xtb
+++ b/ash/strings/ash_strings_th.xtb
@@ -23,6 +23,7 @@
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">ตัวเรียกใช้งาน</translation>
 <translation id="1525508553941733066">ปิด</translation>
+<translation id="1537254971476575106">แว่นขยายทั้งหน้าจอ</translation>
 <translation id="15373452373711364">เคอร์เซอร์เมาส์ขนาดใหญ่</translation>
 <translation id="1550523713251050646">คลิกเพื่อดูตัวเลือกเพิ่มเติม</translation>
 <translation id="1567387640189251553">มีการเชื่อมต่อกับแป้นพิมพ์อื่นหลังจากที่คุณป้อนรหัสผ่านครั้งล่าสุด แป้นพิมพ์นี้อาจพยายามขโมยการกดแป้นพิมพ์ของคุณ</translation>
@@ -51,10 +52,11 @@
 <translation id="2049639323467105390">อุปกรณ์นี้ได้รับการจัดการโดย <ph name="DOMAIN" /></translation>
 <translation id="2050339315714019657">แนวตั้ง</translation>
 <translation id="2067602449040652523">ความสว่างของแป้นพิมพ์</translation>
+<translation id="2081529251031312395">$1 ลงชื่อเข้าใช้ภายหลังได้</translation>
 <translation id="2122028596993374965">หยุดแคสต์ <ph name="TAB_NAME" /> ไปยัง <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">ที่ชาร์จพลังงานต่ำ</translation>
+<translation id="2135456203358955318">แว่นขยายหน้าจอบางส่วน</translation>
 <translation id="2144487987174258011">รีสตาร์ทเพื่ออัปเดต Adobe Flash Player</translation>
-<translation id="2191905770366256395">แป้มพิมพ์ที่ถอดได้ต้องได้รับอัปเดตที่สำคัญ</translation>
 <translation id="2208323208084708176">โหมดเดสก์ท็อปแบบรวม</translation>
 <translation id="2220572644011485463">PIN หรือรหัสผ่าน</translation>
 <translation id="225680501294068881">กำลังสแกนหาอุปกรณ์...</translation>
diff --git a/ash/strings/ash_strings_tr.xtb b/ash/strings/ash_strings_tr.xtb
index cb53793..ed8861e 100644
--- a/ash/strings/ash_strings_tr.xtb
+++ b/ash/strings/ash_strings_tr.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965"><ph name="TAB_NAME" /> sekmesinin <ph name="RECEIVER_NAME" /> cihazına yayınını durdur</translation>
 <translation id="2127372758936585790">Düşük güçlü şarj cihazı</translation>
 <translation id="2144487987174258011">Adobe Flash Player'ı güncellemek için yeniden başlatın</translation>
-<translation id="2191905770366256395">Çıkarılabilir klavyenizde kritik bir güncelleme yapılması gerekiyor</translation>
 <translation id="2208323208084708176">Birleştirilmiş masaüstü modu</translation>
 <translation id="2220572644011485463">PIN veya şifre</translation>
 <translation id="225680501294068881">Cihazlar taranıyor...</translation>
diff --git a/ash/strings/ash_strings_uk.xtb b/ash/strings/ash_strings_uk.xtb
index c9b0a7c..42f1dbc 100644
--- a/ash/strings/ash_strings_uk.xtb
+++ b/ash/strings/ash_strings_uk.xtb
@@ -57,7 +57,6 @@
 <translation id="2127372758936585790">Зарядний пристрій низької потужності</translation>
 <translation id="2135456203358955318">Закріплена лупа</translation>
 <translation id="2144487987174258011">Перезапустіть Chrome, щоб оновити Adobe Flash Player</translation>
-<translation id="2191905770366256395">Знімну клавіатуру потрібно оновити</translation>
 <translation id="2208323208084708176">Режим уніфікованого комп’ютера</translation>
 <translation id="2220572644011485463">PIN-код або пароль</translation>
 <translation id="225680501294068881">Пошук пристроїв...</translation>
diff --git a/ash/strings/ash_strings_vi.xtb b/ash/strings/ash_strings_vi.xtb
index e70948f..e33f757 100644
--- a/ash/strings/ash_strings_vi.xtb
+++ b/ash/strings/ash_strings_vi.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">Dừng truyền <ph name="TAB_NAME" /> sang <ph name="RECEIVER_NAME" /></translation>
 <translation id="2127372758936585790">Bộ sạc công suất thấp</translation>
 <translation id="2144487987174258011">Khởi động lại để cập nhật Adobe Flash Player</translation>
-<translation id="2191905770366256395">Bàn phím có thể tháo rời của bạn cần có một bản cập nhật quan trọng</translation>
 <translation id="2208323208084708176">Chế độ màn hình đồng nhất</translation>
 <translation id="2220572644011485463">Mã PIN hoặc mật khẩu</translation>
 <translation id="225680501294068881">Đang quét tìm thiết bị...</translation>
diff --git a/ash/strings/ash_strings_zh-CN.xtb b/ash/strings/ash_strings_zh-CN.xtb
index 45a2b28c..df25673 100644
--- a/ash/strings/ash_strings_zh-CN.xtb
+++ b/ash/strings/ash_strings_zh-CN.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">停止将<ph name="TAB_NAME" />投射到“<ph name="RECEIVER_NAME" />”</translation>
 <translation id="2127372758936585790">低功率充电器</translation>
 <translation id="2144487987174258011">请重新启动以更新 Adobe Flash Player</translation>
-<translation id="2191905770366256395">您的可拆卸式键盘需要安装一项重要更新</translation>
 <translation id="2208323208084708176">统一桌面模式</translation>
 <translation id="2220572644011485463">PIN 码或密码</translation>
 <translation id="225680501294068881">正在查找设备...</translation>
diff --git a/ash/strings/ash_strings_zh-TW.xtb b/ash/strings/ash_strings_zh-TW.xtb
index 799e6fd..f926030 100644
--- a/ash/strings/ash_strings_zh-TW.xtb
+++ b/ash/strings/ash_strings_zh-TW.xtb
@@ -54,7 +54,6 @@
 <translation id="2122028596993374965">停止將 <ph name="TAB_NAME" /> 投放到「<ph name="RECEIVER_NAME" />」</translation>
 <translation id="2127372758936585790">低功率充電器</translation>
 <translation id="2144487987174258011">重新啟動以便更新 Adobe Flash Player</translation>
-<translation id="2191905770366256395">你的卸除式鍵盤需進行重大更新</translation>
 <translation id="2208323208084708176">整合桌面模式</translation>
 <translation id="2220572644011485463">PIN 或密碼</translation>
 <translation id="225680501294068881">正在掃描裝置...</translation>
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index c087bc4..05bfb6e 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -354,9 +354,9 @@
 
     // In the horizontal case, message center starts from the top of the shelf.
     // In the vertical case, it starts from the bottom of WebNotificationTray.
-    const int max_height =
-        (shelf()->IsHorizontalAlignment() ? shelf()->GetIdealBounds().y()
-                                          : GetBoundsInScreen().bottom());
+    const int max_height = (shelf()->IsHorizontalAlignment()
+                                ? shelf()->GetUserWorkAreaBounds().height()
+                                : GetBoundsInScreen().bottom());
     // Sets the maximum height, considering the padding from the top edge of
     // screen. This padding should be applied in all types of shelf alignment.
     message_center_bubble->SetMaxHeight(max_height - kPaddingFromScreenTop);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6f366789..7e87691 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -513,6 +513,8 @@
     "memory/memory_pressure_monitor_mac.h",
     "memory/memory_pressure_monitor_win.cc",
     "memory/memory_pressure_monitor_win.h",
+    "memory/platform_shared_memory_region.cc",
+    "memory/platform_shared_memory_region.h",
     "memory/protected_memory.cc",
     "memory/protected_memory.h",
     "memory/protected_memory_cfi.h",
@@ -520,6 +522,8 @@
     "memory/protected_memory_win.cc",
     "memory/ptr_util.h",
     "memory/raw_scoped_refptr_mismatch_checker.h",
+    "memory/read_only_shared_memory_region.cc",
+    "memory/read_only_shared_memory_region.h",
     "memory/ref_counted.cc",
     "memory/ref_counted.h",
     "memory/ref_counted_delete_on_sequence.h",
@@ -532,11 +536,17 @@
     "memory/shared_memory_handle.h",
     "memory/shared_memory_helper.cc",
     "memory/shared_memory_helper.h",
+    "memory/shared_memory_mapping.cc",
+    "memory/shared_memory_mapping.h",
     "memory/shared_memory_tracker.cc",
     "memory/shared_memory_tracker.h",
     "memory/singleton.h",
+    "memory/unsafe_shared_memory_region.cc",
+    "memory/unsafe_shared_memory_region.h",
     "memory/weak_ptr.cc",
     "memory/weak_ptr.h",
+    "memory/writable_shared_memory_region.cc",
+    "memory/writable_shared_memory_region.h",
     "message_loop/incoming_task_queue.cc",
     "message_loop/incoming_task_queue.h",
     "message_loop/message_loop.cc",
@@ -1231,6 +1241,7 @@
   if (is_android) {
     sources -= [ "debug/stack_trace_posix.cc" ]
     sources += [
+      "memory/platform_shared_memory_region_android.cc",
       "memory/shared_memory_android.cc",
       "memory/shared_memory_handle_android.cc",
       "time/time_android.cc",
@@ -1298,6 +1309,7 @@
       "fuchsia/fuchsia_logging.cc",
       "fuchsia/fuchsia_logging.h",
       "fuchsia/scoped_zx_handle.h",
+      "memory/platform_shared_memory_region_fuchsia.cc",
       "memory/shared_memory_fuchsia.cc",
       "memory/shared_memory_handle_fuchsia.cc",
       "message_loop/message_pump_fuchsia.cc",
@@ -1440,6 +1452,7 @@
   # Windows.
   if (is_win) {
     sources += [
+      "memory/platform_shared_memory_region_win.cc",
       "memory/shared_memory_handle_win.cc",
       "memory/shared_memory_win.cc",
       "power_monitor/power_monitor_device_source_win.cc",
@@ -1560,6 +1573,7 @@
     sources -= [ "profiler/native_stack_sampler_posix.cc" ]
     sources += [
       "mac/scoped_typeref.h",
+      "memory/platform_shared_memory_region_mac.cc",
       "memory/shared_memory_handle_mac.cc",
       "memory/shared_memory_mac.cc",
       "power_monitor/power_monitor_device_source_mac.mm",
@@ -1712,7 +1726,10 @@
   # Android, Fuchsia, and MacOS have their own custom shared memory handle
   # implementations. e.g. due to supporting both POSIX and native handles.
   if (is_posix && !is_android && !is_fuchsia && !is_mac) {
-    sources += [ "memory/shared_memory_handle_posix.cc" ]
+    sources += [
+      "memory/platform_shared_memory_region_posix.cc",
+      "memory/shared_memory_handle_posix.cc",
+    ]
   }
 
   if (is_posix && !is_fuchsia && !is_mac && !is_nacl) {
@@ -2198,11 +2215,13 @@
     "memory/memory_pressure_monitor_mac_unittest.cc",
     "memory/memory_pressure_monitor_unittest.cc",
     "memory/memory_pressure_monitor_win_unittest.cc",
+    "memory/platform_shared_memory_region_unittest.cc",
     "memory/protected_memory_unittest.cc",
     "memory/ptr_util_unittest.cc",
     "memory/ref_counted_memory_unittest.cc",
     "memory/ref_counted_unittest.cc",
     "memory/shared_memory_mac_unittest.cc",
+    "memory/shared_memory_region_unittest.cc",
     "memory/shared_memory_unittest.cc",
     "memory/shared_memory_win_unittest.cc",
     "memory/singleton_unittest.cc",
diff --git a/base/android/early_trace_event_binding.cc b/base/android/early_trace_event_binding.cc
index 53e40c5..bf6b910 100644
--- a/base/android/early_trace_event_binding.cc
+++ b/base/android/early_trace_event_binding.cc
@@ -35,5 +35,33 @@
       TRACE_EVENT_FLAG_COPY);
 }
 
+static void JNI_EarlyTraceEvent_RecordEarlyStartAsyncEvent(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& jname,
+    jlong id,
+    jlong timestamp_ns) {
+  std::string name = ConvertJavaStringToUTF8(env, jname);
+  int64_t timestamp_us = timestamp_ns / 1000;
+
+  TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(
+      kEarlyJavaCategory, name.c_str(), id,
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(timestamp_us));
+}
+
+static void JNI_EarlyTraceEvent_RecordEarlyFinishAsyncEvent(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& jname,
+    jlong id,
+    jlong timestamp_ns) {
+  std::string name = ConvertJavaStringToUTF8(env, jname);
+  int64_t timestamp_us = timestamp_ns / 1000;
+
+  TRACE_EVENT_COPY_ASYNC_END_WITH_TIMESTAMP0(
+      kEarlyJavaCategory, name.c_str(), id,
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(timestamp_us));
+}
+
 }  // namespace android
 }  // namespace base
diff --git a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
index 7955359..0701814 100644
--- a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
+++ b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
@@ -76,6 +76,21 @@
         }
     }
 
+    @VisibleForTesting
+    static final class AsyncEvent {
+        final boolean mIsStart;
+        final String mName;
+        final long mId;
+        final long mTimestampNanos;
+
+        AsyncEvent(String name, long id, boolean isStart) {
+            mName = name;
+            mId = id;
+            mIsStart = isStart;
+            mTimestampNanos = Event.elapsedRealtimeNanos();
+        }
+    }
+
     // State transitions are:
     // - enable(): DISABLED -> ENABLED
     // - disable(): ENABLED -> FINISHING
@@ -92,6 +107,7 @@
     // Not final as these object are not likely to be used at all.
     @VisibleForTesting static List<Event> sCompletedEvents;
     @VisibleForTesting static Map<String, Event> sPendingEvents;
+    @VisibleForTesting static List<AsyncEvent> sAsyncEvents;
 
     /** @see TraceEvent#MaybeEnableEarlyTracing().
      */
@@ -122,6 +138,7 @@
             if (sState != STATE_DISABLED) return;
             sCompletedEvents = new ArrayList<Event>();
             sPendingEvents = new HashMap<String, Event>();
+            sAsyncEvents = new ArrayList<AsyncEvent>();
             sState = STATE_ENABLED;
         }
     }
@@ -185,11 +202,32 @@
         }
     }
 
+    /** @see {@link TraceEvent#startAsync()}. */
+    public static void startAsync(String name, long id) {
+        if (!enabled()) return;
+        AsyncEvent event = new AsyncEvent(name, id, true /*isStart*/);
+        synchronized (sLock) {
+            if (!enabled()) return;
+            sAsyncEvents.add(event);
+        }
+    }
+
+    /** @see {@link TraceEvent#finishAsync()}. */
+    public static void finishAsync(String name, long id) {
+        if (!enabled()) return;
+        AsyncEvent event = new AsyncEvent(name, id, false /*isStart*/);
+        synchronized (sLock) {
+            if (!enabled()) return;
+            sAsyncEvents.add(event);
+        }
+    }
+
     @VisibleForTesting
     static void resetForTesting() {
         sState = EarlyTraceEvent.STATE_DISABLED;
         sCompletedEvents = null;
         sPendingEvents = null;
+        sAsyncEvents = null;
     }
 
     private static void maybeFinishLocked() {
@@ -197,6 +235,10 @@
             dumpEvents(sCompletedEvents);
             sCompletedEvents.clear();
         }
+        if (!sAsyncEvents.isEmpty()) {
+            dumpAsyncEvents(sAsyncEvents);
+            sAsyncEvents.clear();
+        }
         if (sPendingEvents.isEmpty()) {
             sState = STATE_FINISHED;
             sPendingEvents = null;
@@ -214,7 +256,23 @@
                     e.mEndThreadTimeMillis - e.mBeginThreadTimeMillis);
         }
     }
+    private static void dumpAsyncEvents(List<AsyncEvent> events) {
+        long nativeNowNanos = TimeUtils.nativeGetTimeTicksNowUs() * 1000;
+        long javaNowNanos = Event.elapsedRealtimeNanos();
+        long offsetNanos = nativeNowNanos - javaNowNanos;
+        for (AsyncEvent e : events) {
+            if (e.mIsStart) {
+                nativeRecordEarlyStartAsyncEvent(e.mName, e.mId, e.mTimestampNanos + offsetNanos);
+            } else {
+                nativeRecordEarlyFinishAsyncEvent(e.mName, e.mId, e.mTimestampNanos + offsetNanos);
+            }
+        }
+    }
 
     private static native void nativeRecordEarlyEvent(String name, long beginTimNanos,
             long endTimeNanos, int threadId, long threadDurationMillis);
+    private static native void nativeRecordEarlyStartAsyncEvent(
+            String name, long id, long timestamp);
+    private static native void nativeRecordEarlyFinishAsyncEvent(
+            String name, long id, long timestamp);
 }
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
index 0710a199..9659090 100644
--- a/base/android/java/src/org/chromium/base/TraceEvent.java
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -324,6 +324,7 @@
      * @param id   The id of the asynchronous event.
      */
     public static void startAsync(String name, long id) {
+        EarlyTraceEvent.startAsync(name, id);
         if (sEnabled) nativeStartAsync(name, id);
     }
 
@@ -333,6 +334,7 @@
      * @param id   The id of the asynchronous event.
      */
     public static void finishAsync(String name, long id) {
+        EarlyTraceEvent.finishAsync(name, id);
         if (sEnabled) nativeFinishAsync(name, id);
     }
 
diff --git a/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
index 128326ac..67f5cc5 100644
--- a/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
+++ b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.base;
 
+import static org.chromium.base.EarlyTraceEvent.AsyncEvent;
+import static org.chromium.base.EarlyTraceEvent.Event;
+
 import android.os.Process;
 import android.support.test.filters.SmallTest;
 
@@ -12,8 +15,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.chromium.base.EarlyTraceEvent.Event;
-
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
@@ -28,6 +29,7 @@
 public class EarlyTraceEventTest {
     private static final String EVENT_NAME = "MyEvent";
     private static final String EVENT_NAME2 = "MyOtherEvent";
+    private static final long EVENT_ID = 1;
 
     @Before
     public void setUp() throws Exception {
@@ -60,6 +62,29 @@
     @Test
     @SmallTest
     @Feature({"Android-AppBase"})
+    public void testCanRecordAsyncEvent() {
+        EarlyTraceEvent.enable();
+        long beforeNanos = Event.elapsedRealtimeNanos();
+        EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID);
+        EarlyTraceEvent.finishAsync(EVENT_NAME, EVENT_ID);
+        long afterNanos = Event.elapsedRealtimeNanos();
+
+        Assert.assertEquals(2, EarlyTraceEvent.sAsyncEvents.size());
+        Assert.assertTrue(EarlyTraceEvent.sPendingEvents.isEmpty());
+        AsyncEvent eventStart = EarlyTraceEvent.sAsyncEvents.get(0);
+        AsyncEvent eventEnd = EarlyTraceEvent.sAsyncEvents.get(1);
+        Assert.assertEquals(EVENT_NAME, eventStart.mName);
+        Assert.assertEquals(EVENT_ID, eventStart.mId);
+        Assert.assertEquals(EVENT_NAME, eventEnd.mName);
+        Assert.assertEquals(EVENT_ID, eventEnd.mId);
+        Assert.assertTrue(beforeNanos <= eventStart.mTimestampNanos
+                && eventEnd.mTimestampNanos <= afterNanos);
+        Assert.assertTrue(eventStart.mTimestampNanos <= eventEnd.mTimestampNanos);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
     public void testCanRecordEventUsingTryWith() {
         EarlyTraceEvent.enable();
         long myThreadId = Process.myTid();
@@ -123,6 +148,15 @@
     @Test
     @SmallTest
     @Feature({"Android-AppBase"})
+    public void testIgnoreAsyncEventsWhenDisabled() {
+        EarlyTraceEvent.startAsync(EVENT_NAME, EVENT_ID);
+        EarlyTraceEvent.finishAsync(EVENT_NAME, EVENT_ID);
+        Assert.assertNull(EarlyTraceEvent.sAsyncEvents);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
     public void testIgnoreNewEventsWhenFinishing() {
         EarlyTraceEvent.enable();
         EarlyTraceEvent.begin(EVENT_NAME);
diff --git a/base/containers/span.h b/base/containers/span.h
index a0710af..dc3f17f 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -142,14 +142,18 @@
 // Differences from the working group proposal
 // -------------------------------------------
 //
-// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0122r5.pdf is the
-// latest working group proposal. The biggest difference is span does not
-// support a static extent template parameter. Other differences are documented
-// in subsections below.
+// https://wg21.link/P0122 is the latest working group proposal, Chromium
+// currently implements R6. The biggest difference is span does not support a
+// static extent template parameter. Other differences are documented in
+// subsections below.
 //
 // Differences from [views.constants]:
 // - no dynamic_extent constant
 //
+// Differences from [span.objectrep]:
+// - no as_bytes()
+// - no as_writeable_bytes()
+//
 // Differences in constants and types:
 // - no element_type type alias
 // - no index_type type alias
@@ -159,26 +163,22 @@
 // Differences from [span.cons]:
 // - no constructor from a pointer range
 // - no constructor from std::array
-// - no constructor from std::unique_ptr
-// - no constructor from std::shared_ptr
-// - no explicitly defaulted the copy/move constructor/assignment operators,
-//   since MSVC complains about constexpr functions that aren't marked const.
 //
 // Differences from [span.sub]:
 // - no templated first()
 // - no templated last()
 // - no templated subspan()
+// - using size_t instead of ptrdiff_t for indexing
 //
 // Differences from [span.obs]:
-// - no length_bytes()
 // - no size_bytes()
+// - using size_t instead of ptrdiff_t to represent size()
 //
 // Differences from [span.elem]:
 // - no operator ()()
-//
-// Differences from [span.objectrep]:
-// - no as_bytes()
-// - no as_writeable_bytes()
+// - using size_t instead of ptrdiff_t for indexing
+
+// [span], class template span
 template <typename T>
 class span {
  public:
@@ -190,9 +190,8 @@
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
-  // span constructors, copy, assignment, and destructor
+  // [span.cons], span constructors, copy, assignment, and destructor
   constexpr span() noexcept : data_(nullptr), size_(0) {}
-  constexpr span(std::nullptr_t) noexcept : span() {}
   constexpr span(T* data, size_t size) noexcept : data_(data), size_(size) {}
   // TODO(dcheng): Implement construction from a |begin| and |end| pointer.
   template <size_t N>
@@ -208,15 +207,15 @@
       typename Container,
       typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>>
   span(const Container& container) : span(container.data(), container.size()) {}
-  ~span() noexcept = default;
+  constexpr span(const span& other) noexcept = default;
   // Conversions from spans of compatible types: this allows a span<T> to be
   // seamlessly used as a span<const T>, but not the other way around.
   template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>>
   constexpr span(const span<U>& other) : span(other.data(), other.size()) {}
-  template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>>
-  constexpr span(span<U>&& other) : span(other.data(), other.size()) {}
+  constexpr span& operator=(const span& other) noexcept = default;
+  ~span() noexcept = default;
 
-  // span subviews
+  // [span.sub], span subviews
   constexpr span first(size_t count) const {
     CHECK(count <= size_);
     return span(data_, count);
@@ -228,36 +227,41 @@
   }
 
   constexpr span subspan(size_t pos, size_t count = -1) const {
+    constexpr auto npos = static_cast<size_t>(-1);
     CHECK(pos <= size_);
-    return span(data_ + pos, std::min(size_ - pos, count));
+    CHECK(count == npos || count <= size_ - pos);
+    return span(data_ + pos, count == npos ? size_ - pos : count);
   }
 
-  // span observers
-  constexpr size_t length() const noexcept { return size_; }
+  // [span.obs], span observers
   constexpr size_t size() const noexcept { return size_; }
   constexpr bool empty() const noexcept { return size_ == 0; }
 
-  // span element access
+  // [span.elem], span element access
   constexpr T& operator[](size_t index) const noexcept {
     CHECK(index < size_);
     return data_[index];
   }
   constexpr T* data() const noexcept { return data_; }
 
-  // span iterator support
-  iterator begin() const noexcept { return data_; }
-  iterator end() const noexcept { return data_ + size_; }
+  // [span.iter], span iterator support
+  constexpr iterator begin() const noexcept { return data_; }
+  constexpr iterator end() const noexcept { return data_ + size_; }
 
-  const_iterator cbegin() const noexcept { return begin(); }
-  const_iterator cend() const noexcept { return end(); }
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+  constexpr const_iterator cend() const noexcept { return end(); }
 
-  reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
-  reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
+  constexpr reverse_iterator rbegin() const noexcept {
+    return reverse_iterator(end());
+  }
+  constexpr reverse_iterator rend() const noexcept {
+    return reverse_iterator(begin());
+  }
 
-  const_reverse_iterator crbegin() const noexcept {
+  constexpr const_reverse_iterator crbegin() const noexcept {
     return const_reverse_iterator(cend());
   }
-  const_reverse_iterator crend() const noexcept {
+  constexpr const_reverse_iterator crend() const noexcept {
     return const_reverse_iterator(cbegin());
   }
 
@@ -266,35 +270,36 @@
   size_t size_;
 };
 
+// [span.comparison], span comparison operators
 // Relational operators. Equality is a element-wise comparison.
 template <typename T>
-constexpr bool operator==(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator==(span<T> lhs, span<T> rhs) noexcept {
   return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
 }
 
 template <typename T>
-constexpr bool operator!=(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator!=(span<T> lhs, span<T> rhs) noexcept {
   return !(lhs == rhs);
 }
 
 template <typename T>
-constexpr bool operator<(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator<(span<T> lhs, span<T> rhs) noexcept {
   return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(),
                                       rhs.cend());
 }
 
 template <typename T>
-constexpr bool operator<=(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator<=(span<T> lhs, span<T> rhs) noexcept {
   return !(rhs < lhs);
 }
 
 template <typename T>
-constexpr bool operator>(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator>(span<T> lhs, span<T> rhs) noexcept {
   return rhs < lhs;
 }
 
 template <typename T>
-constexpr bool operator>=(const span<T>& lhs, const span<T>& rhs) noexcept {
+constexpr bool operator>=(span<T> lhs, span<T> rhs) noexcept {
   return !(lhs < rhs);
 }
 
diff --git a/base/containers/span_unittest.cc b/base/containers/span_unittest.cc
index 0ec2b8b2..be75a94 100644
--- a/base/containers/span_unittest.cc
+++ b/base/containers/span_unittest.cc
@@ -19,8 +19,8 @@
 
 namespace base {
 
-TEST(SpanTest, ConstructFromNullptr) {
-  span<int> span(nullptr);
+TEST(SpanTest, DefaultConstructor) {
+  span<int> span;
   EXPECT_EQ(nullptr, span.data());
   EXPECT_EQ(0u, span.size());
 }
@@ -295,19 +295,6 @@
   }
 }
 
-TEST(SpanTest, Length) {
-  {
-    span<int> span;
-    EXPECT_EQ(0u, span.length());
-  }
-
-  {
-    int array[] = {1, 2, 3};
-    span<int> span(array);
-    EXPECT_EQ(3u, span.length());
-  }
-}
-
 TEST(SpanTest, Size) {
   {
     span<int> span;
diff --git a/base/memory/platform_shared_memory_region.cc b/base/memory/platform_shared_memory_region.cc
new file mode 100644
index 0000000..ae2e110a
--- /dev/null
+++ b/base/memory/platform_shared_memory_region.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include "base/memory/shared_memory_mapping.h"
+
+namespace base {
+namespace subtle {
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateWritable(
+    size_t size) {
+  return Create(Mode::kWritable, size);
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateUnsafe(
+    size_t size) {
+  return Create(Mode::kUnsafe, size);
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion() = default;
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    PlatformSharedMemoryRegion&& other) = default;
+PlatformSharedMemoryRegion& PlatformSharedMemoryRegion::operator=(
+    PlatformSharedMemoryRegion&& other) = default;
+PlatformSharedMemoryRegion::~PlatformSharedMemoryRegion() = default;
+
+PlatformSharedMemoryRegion::ScopedPlatformHandle
+PlatformSharedMemoryRegion::PassPlatformHandle() {
+  return std::move(handle_);
+}
+
+// static
+bool PlatformSharedMemoryRegion::CheckPlatformHandlePermissionsCorrespondToMode(
+    PlatformHandle handle,
+    Mode mode,
+    size_t size) {
+  // TODO(https://crbug.com/825177): implement this in platform-specific way.
+  return true;
+}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region.h b/base/memory/platform_shared_memory_region.h
new file mode 100644
index 0000000..39bf240
--- /dev/null
+++ b/base/memory/platform_shared_memory_region.h
@@ -0,0 +1,219 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
+
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+#include "base/mac/scoped_mach_port.h"
+#elif defined(OS_FUCHSIA)
+#include "base/fuchsia/scoped_zx_handle.h"
+#elif defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_types.h"
+#elif defined(OS_POSIX)
+#include <sys/types.h>
+#include "base/file_descriptor_posix.h"
+#include "base/files/scoped_file.h"
+#endif
+
+namespace base {
+namespace subtle {
+
+#if defined(OS_POSIX) && (!defined(OS_MACOSX) || defined(OS_IOS)) && \
+    !defined(OS_FUCHSIA) && !defined(OS_ANDROID)
+// Helper structs to keep two descriptors on POSIX. It's needed to support
+// ConvertToReadOnly().
+struct BASE_EXPORT FDPair {
+  int fd;
+  int readonly_fd;
+};
+
+struct BASE_EXPORT ScopedFDPair {
+  ScopedFDPair();
+  ScopedFDPair(ScopedFD in_fd, ScopedFD in_readonly_fd);
+  ScopedFDPair(ScopedFDPair&&);
+  ScopedFDPair& operator=(ScopedFDPair&&);
+  ~ScopedFDPair();
+
+  FDPair get() const;
+
+  ScopedFD fd;
+  ScopedFD readonly_fd;
+};
+#endif
+
+// Implementation class for shared memory regions.
+//
+// This class does the following:
+//
+// - Wraps and owns a shared memory region platform handle.
+// - Provides a way to allocate a new region of platform shared memory of given
+//   size.
+// - Provides a way to create mapping of the region in the current process'
+//   address space, under special access-control constraints (see Mode).
+// - Provides methods to help transferring the handle across process boundaries.
+// - Holds a 128-bit unique identifier used to uniquely identify the same
+//   kernel region resource across processes (used for memory tracking).
+// - Has a method to retrieve the region's size in bytes.
+//
+// IMPORTANT NOTE: Users should never use this directly, but
+// ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
+// UnsafeSharedMemoryRegion since this is an implementation class.
+class BASE_EXPORT PlatformSharedMemoryRegion {
+ public:
+  // Permission mode of the platform handle. Each mode corresponds to one of the
+  // typed shared memory classes:
+  //
+  // * ReadOnlySharedMemoryRegion: A region that can only create read-only
+  // mappings.
+  //
+  // * WritableSharedMemoryRegion: A region that can only create writable
+  // mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
+  // the possibility of promoting back to writable.
+  //
+  // * UnsafeSharedMemoryRegion: A region that can only create writable
+  // mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
+  enum class Mode {
+    kReadOnly,  // ReadOnlySharedMemoryRegion
+    kWritable,  // WritableSharedMemoryRegion
+    kUnsafe,    // UnsafeSharedMemoryRegion
+  };
+
+// Platform-specific shared memory type used by this class.
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  using PlatformHandle = mach_port_t;
+  using ScopedPlatformHandle = mac::ScopedMachSendRight;
+#elif defined(OS_FUCHSIA)
+  using PlatformHandle = zx_handle_t;
+  using ScopedPlatformHandle = ScopedZxHandle;
+#elif defined(OS_WIN)
+  using PlatformHandle = HANDLE;
+  using ScopedPlatformHandle = win::ScopedHandle;
+#elif defined(OS_ANDROID)
+  using PlatformHandle = int;
+  using ScopedPlatformHandle = ScopedFD;
+#else
+  using PlatformHandle = FDPair;
+  using ScopedPlatformHandle = ScopedFDPair;
+#endif
+
+  // The minimum alignment in bytes that any mapped address produced by Map()
+  // and MapAt() is guaranteed to have.
+  enum { kMapMinimumAlignment = 32 };
+
+  // Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
+  // Creating in kReadOnly mode isn't supported because then there will be no
+  // way to modify memory content.
+  static PlatformSharedMemoryRegion CreateWritable(size_t size);
+  static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
+
+  // Returns a new PlatformSharedMemoryRegion that takes ownership of the
+  // |handle|. All parameters must be taken from another valid
+  // PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
+  // actual region size as allocated by the kernel.
+  // Closes the |handle| and returns an invalid instance if passed parameters
+  // are invalid.
+  static PlatformSharedMemoryRegion Take(ScopedPlatformHandle handle,
+                                         Mode mode,
+                                         size_t size,
+                                         const UnguessableToken& guid);
+
+  // Default constructor initializes an invalid instance, i.e. an instance that
+  // doesn't wrap any valid platform handle.
+  PlatformSharedMemoryRegion();
+
+  // Move operations are allowed.
+  PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
+  PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
+
+  // Destructor closes the platform handle. Does nothing if the handle is
+  // invalid.
+  ~PlatformSharedMemoryRegion();
+
+  // Passes ownership of the platform handle to the caller. The current instance
+  // becomes invalid. It's the responsibility of the caller to close the handle.
+  ScopedPlatformHandle PassPlatformHandle() WARN_UNUSED_RESULT;
+
+  // Returns the platform handle. The current instance keeps ownership of this
+  // handle.
+  PlatformHandle GetPlatformHandle() const;
+
+  // Whether the platform handle is valid.
+  bool IsValid() const;
+
+  // Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
+  // with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
+  // invalid region on failure, the current instance remains valid.
+  // Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
+  // called in kWritable mode.
+  PlatformSharedMemoryRegion Duplicate();
+
+  // Converts the region to read-only. Returns whether the operation succeeded.
+  // Makes the current instance invalid on failure. Can be called only in
+  // kWritable mode, all other modes will CHECK-fail. The object will have
+  // kReadOnly mode after this call on success.
+  bool ConvertToReadOnly();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // Same as above, but |mapped_addr| is used as a hint to avoid additional
+  // mapping of the memory object.
+  // |mapped_addr| must be mapped location of |memory_object_|. If the location
+  // is unknown, |mapped_addr| should be |nullptr|.
+  bool ConvertToReadOnly(void* mapped_addr);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+  // Maps |size| bytes of the shared memory region starting with the given
+  // |offset| into the caller's address space. |offset| must be aligned to value
+  // of |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out
+  // of the region limits.
+  // Returns true and sets |memory| and |mapped_size| on success, returns false
+  // and leaves output parameters in unspecified state otherwise. The mapped
+  // address is guaranteed to have an alignment of at least
+  // |kMapMinimumAlignment|.
+  bool MapAt(off_t offset, size_t size, void** memory, size_t* mapped_size);
+
+  const UnguessableToken& GetGUID() const { return guid_; }
+
+  size_t GetSize() const { return size_; }
+
+  Mode GetMode() const { return mode_; }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
+                           CreateReadOnlyRegionDeathTest);
+  FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
+                           CheckPlatformHandlePermissionsCorrespondToMode);
+  static PlatformSharedMemoryRegion Create(Mode mode, size_t size);
+
+  static bool CheckPlatformHandlePermissionsCorrespondToMode(
+      PlatformHandle handle,
+      Mode mode,
+      size_t size);
+
+  PlatformSharedMemoryRegion(ScopedPlatformHandle handle,
+                             Mode mode,
+                             size_t size,
+                             const UnguessableToken& guid);
+
+  ScopedPlatformHandle handle_;
+  Mode mode_ = Mode::kReadOnly;
+  size_t size_ = 0;
+  UnguessableToken guid_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformSharedMemoryRegion);
+};
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
diff --git a/base/memory/platform_shared_memory_region_android.cc b/base/memory/platform_shared_memory_region_android.cc
new file mode 100644
index 0000000..f8c13aa
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_android.cc
@@ -0,0 +1,170 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <sys/mman.h>
+
+#include "base/memory/shared_memory_tracker.h"
+#include "base/posix/eintr_wrapper.h"
+#include "third_party/ashmem/ashmem.h"
+
+namespace base {
+namespace subtle {
+
+// For Android, we use ashmem to implement SharedMemory. ashmem_create_region
+// will automatically pin the region. We never explicitly call pin/unpin. When
+// all the file descriptors from different processes associated with the region
+// are closed, the memory buffer will go away.
+
+namespace {
+
+static int GetAshmemRegionProtectionMask(int fd) {
+  int prot = ashmem_get_prot_region(fd);
+  if (prot < 0) {
+    DPLOG(ERROR) << "ashmem_get_prot_region failed";
+    return -1;
+  }
+  return prot;
+}
+
+}  // namespace
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+    ScopedFD fd,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid) {
+  if (!fd.is_valid())
+    return {};
+
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK(CheckPlatformHandlePermissionsCorrespondToMode(fd.get(), mode, size));
+
+  return PlatformSharedMemoryRegion(std::move(fd), mode, size, guid);
+}
+
+int PlatformSharedMemoryRegion::GetPlatformHandle() const {
+  return handle_.get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+  return handle_.is_valid();
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() {
+  if (!IsValid())
+    return {};
+
+  CHECK_NE(mode_, Mode::kWritable)
+      << "Duplicating a writable shared memory region is prohibited";
+
+  ScopedFD duped_fd(HANDLE_EINTR(dup(handle_.get())));
+  if (!duped_fd.is_valid()) {
+    DPLOG(ERROR) << "dup(" << handle_.get() << ") failed";
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(duped_fd), mode_, size_, guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+  if (!IsValid())
+    return false;
+
+  CHECK_EQ(mode_, Mode::kWritable)
+      << "Only writable shared memory region can be converted to read-only";
+
+  ScopedFD handle_copy(handle_.release());
+
+  int prot = GetAshmemRegionProtectionMask(handle_copy.get());
+  if (prot < 0)
+    return false;
+
+  prot &= ~PROT_WRITE;
+  int ret = ashmem_set_prot_region(handle_copy.get(), prot);
+  if (ret != 0) {
+    DPLOG(ERROR) << "ashmem_set_prot_region failed";
+    return false;
+  }
+
+  handle_ = std::move(handle_copy);
+  mode_ = Mode::kReadOnly;
+  return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+                                       size_t size,
+                                       void** memory,
+                                       size_t* mapped_size) {
+  if (!IsValid())
+    return false;
+
+  size_t end_byte;
+  if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+    return false;
+  }
+
+  bool write_allowed = mode_ != Mode::kReadOnly;
+  *memory = mmap(nullptr, size, PROT_READ | (write_allowed ? PROT_WRITE : 0),
+                 MAP_SHARED, handle_.get(), offset);
+
+  bool mmap_succeeded = *memory && *memory != reinterpret_cast<void*>(-1);
+  if (!mmap_succeeded) {
+    DPLOG(ERROR) << "mmap " << handle_.get() << " failed";
+    return false;
+  }
+
+  *mapped_size = size;
+  DCHECK_EQ(0U,
+            reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+  return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+                                                              size_t size) {
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  LOG(ERROR) << "Before CHECK";
+  CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+                                     "lead to this region being non-modifiable";
+
+  UnguessableToken guid = UnguessableToken::Create();
+
+  ScopedFD fd(ashmem_create_region(
+      SharedMemoryTracker::GetDumpNameForTracing(guid).c_str(), size));
+  if (!fd.is_valid()) {
+    DPLOG(ERROR) << "ashmem_create_region failed";
+    return {};
+  }
+
+  int err = ashmem_set_prot_region(fd.get(), PROT_READ | PROT_WRITE);
+  if (err < 0) {
+    DPLOG(ERROR) << "ashmem_set_prot_region failed";
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(fd), mode, size, guid);
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    ScopedFD fd,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid)
+    : handle_(std::move(fd)), mode_(mode), size_(size), guid_(guid) {}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region_fuchsia.cc b/base/memory/platform_shared_memory_region_fuchsia.cc
new file mode 100644
index 0000000..f5113e8
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_fuchsia.cc
@@ -0,0 +1,163 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <zircon/process.h>
+#include <zircon/rights.h>
+#include <zircon/syscalls.h>
+
+#include "base/bits.h"
+#include "base/numerics/checked_math.h"
+#include "base/process/process_metrics.h"
+
+namespace base {
+namespace subtle {
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+    ScopedZxHandle handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid) {
+  if (!handle.is_valid())
+    return {};
+
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK(
+      CheckPlatformHandlePermissionsCorrespondToMode(handle.get(), mode, size));
+
+  return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
+}
+
+zx_handle_t PlatformSharedMemoryRegion::GetPlatformHandle() const {
+  return handle_.get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+  return handle_.is_valid();
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() {
+  if (!IsValid())
+    return {};
+
+  CHECK_NE(mode_, Mode::kWritable)
+      << "Duplicating a writable shared memory region is prohibited";
+
+  ScopedZxHandle duped_handle;
+  zx_status_t status = zx_handle_duplicate(handle_.get(), ZX_RIGHT_SAME_RIGHTS,
+                                           duped_handle.receive());
+  if (status != ZX_OK) {
+    DLOG(ERROR) << "zx_handle_duplicate failed: "
+                << zx_status_get_string(status);
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(duped_handle), mode_, size_,
+                                    guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+  if (!IsValid())
+    return false;
+
+  CHECK_EQ(mode_, Mode::kWritable)
+      << "Only writable shared memory region can be converted to read-only";
+
+  ScopedZxHandle old_handle(handle_.release());
+  ScopedZxHandle new_handle;
+  const int kNoWriteOrExec =
+      ZX_DEFAULT_VMO_RIGHTS &
+      ~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY);
+  zx_status_t status =
+      zx_handle_replace(old_handle.get(), kNoWriteOrExec, new_handle.receive());
+  if (status != ZX_OK) {
+    DLOG(ERROR) << "zx_handle_replace failed: " << zx_status_get_string(status);
+    return false;
+  }
+  ignore_result(old_handle.release());
+
+  handle_ = std::move(new_handle);
+  mode_ = Mode::kReadOnly;
+  return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+                                       size_t size,
+                                       void** memory,
+                                       size_t* mapped_size) {
+  if (!IsValid())
+    return false;
+
+  size_t end_byte;
+  if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+    return false;
+  }
+
+  bool write_allowed = mode_ != Mode::kReadOnly;
+  uintptr_t addr;
+  zx_status_t status = zx_vmar_map(
+      zx_vmar_root_self(), 0, handle_.get(), offset, size,
+      ZX_VM_FLAG_PERM_READ | (write_allowed ? ZX_VM_FLAG_PERM_WRITE : 0),
+      &addr);
+  if (status != ZX_OK) {
+    DLOG(ERROR) << "zx_vmar_map failed: " << zx_status_get_string(status);
+    return false;
+  }
+
+  *memory = reinterpret_cast<void*>(addr);
+  *mapped_size = size;
+  DCHECK_EQ(0U,
+            reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+  return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+                                                              size_t size) {
+  if (size == 0)
+    return {};
+
+  size_t rounded_size = bits::Align(size, GetPageSize());
+  if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+                                     "lead to this region being non-modifiable";
+
+  ScopedZxHandle vmo;
+  zx_status_t status = zx_vmo_create(rounded_size, 0, vmo.receive());
+  if (status != ZX_OK) {
+    DLOG(ERROR) << "zx_vmo_create failed: " << zx_status_get_string(status);
+    return {};
+  }
+
+  const int kNoExecFlags = ZX_DEFAULT_VMO_RIGHTS & ~ZX_RIGHT_EXECUTE;
+  ScopedZxHandle old_vmo(std::move(vmo));
+  status = zx_handle_replace(old_vmo.get(), kNoExecFlags, vmo.receive());
+  if (status != ZX_OK) {
+    DLOG(ERROR) << "zx_handle_replace failed: " << zx_status_get_string(status);
+    return {};
+  }
+  ignore_result(old_vmo.release());
+
+  return PlatformSharedMemoryRegion(std::move(vmo), mode, rounded_size,
+                                    UnguessableToken::Create());
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    ScopedZxHandle handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid)
+    : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region_mac.cc b/base/memory/platform_shared_memory_region_mac.cc
new file mode 100644
index 0000000..a6ac91e
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_mac.cc
@@ -0,0 +1,186 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <mach/mach_vm.h>
+
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/numerics/checked_math.h"
+#include "build/build_config.h"
+
+#if defined(OS_IOS)
+#error "MacOS only - iOS uses platform_shared_memory_region_posix.cc"
+#endif
+
+namespace base {
+namespace subtle {
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+    mac::ScopedMachSendRight handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid) {
+  if (!handle.is_valid())
+    return {};
+
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK(
+      CheckPlatformHandlePermissionsCorrespondToMode(handle.get(), mode, size));
+
+  return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
+}
+
+mach_port_t PlatformSharedMemoryRegion::GetPlatformHandle() const {
+  return handle_.get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+  return handle_.is_valid();
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() {
+  if (!IsValid())
+    return {};
+
+  CHECK_NE(mode_, Mode::kWritable)
+      << "Duplicating a writable shared memory region is prohibited";
+
+  // Increment the ref count.
+  kern_return_t kr = mach_port_mod_refs(mach_task_self(), handle_.get(),
+                                        MACH_PORT_RIGHT_SEND, 1);
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(ERROR, kr) << "mach_port_mod_refs";
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(mac::ScopedMachSendRight(handle_.get()),
+                                    mode_, size_, guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+  return ConvertToReadOnly(nullptr);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly(void* mapped_addr) {
+  if (!IsValid())
+    return false;
+
+  CHECK_EQ(mode_, Mode::kWritable)
+      << "Only writable shared memory region can be converted to read-only";
+
+  mac::ScopedMachSendRight handle_copy(handle_.release());
+
+  void* temp_addr = mapped_addr;
+  mac::ScopedMachVM scoped_memory;
+  if (!temp_addr) {
+    // Intentionally lower current prot and max prot to |VM_PROT_READ|.
+    kern_return_t kr = mach_vm_map(
+        mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&temp_addr),
+        size_, 0, VM_FLAGS_ANYWHERE, handle_copy.get(), 0, FALSE, VM_PROT_READ,
+        VM_PROT_READ, VM_INHERIT_NONE);
+    if (kr != KERN_SUCCESS) {
+      MACH_DLOG(ERROR, kr) << "mach_vm_map";
+      return false;
+    }
+    scoped_memory.reset(reinterpret_cast<vm_address_t>(temp_addr),
+                        mach_vm_round_page(size_));
+  }
+
+  // Make new memory object.
+  mac::ScopedMachSendRight named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size_),
+      reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
+      named_right.receive(), MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(ERROR, kr) << "mach_make_memory_entry_64";
+    return false;
+  }
+
+  handle_ = std::move(named_right);
+  mode_ = Mode::kReadOnly;
+  return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+                                       size_t size,
+                                       void** memory,
+                                       size_t* mapped_size) {
+  if (!IsValid())
+    return false;
+
+  size_t end_byte;
+  if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+    return false;
+  }
+
+  bool write_allowed = mode_ != Mode::kReadOnly;
+  vm_prot_t vm_prot_write = write_allowed ? VM_PROT_WRITE : 0;
+  kern_return_t kr = mach_vm_map(
+      mach_task_self(),
+      reinterpret_cast<mach_vm_address_t*>(memory),  // Output parameter
+      size,
+      0,  // Alignment mask
+      VM_FLAGS_ANYWHERE, handle_.get(), offset,
+      FALSE,                         // Copy
+      VM_PROT_READ | vm_prot_write,  // Current protection
+      VM_PROT_READ | vm_prot_write,  // Maximum protection
+      VM_INHERIT_NONE);
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(ERROR, kr) << "mach_vm_map";
+    return false;
+  }
+
+  *mapped_size = size;
+  DCHECK_EQ(0U,
+            reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+  return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+                                                              size_t size) {
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+                                     "lead to this region being non-modifiable";
+
+  mach_vm_size_t vm_size = size;
+  mac::ScopedMachSendRight named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(), &vm_size,
+      0,  // Address.
+      MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE,
+      named_right.receive(),
+      MACH_PORT_NULL);  // Parent handle.
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(ERROR, kr) << "mach_make_memory_entry_64";
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(named_right), mode, vm_size,
+                                    UnguessableToken::Create());
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    mac::ScopedMachSendRight handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid)
+    : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region_posix.cc b/base/memory/platform_shared_memory_region_posix.cc
new file mode 100644
index 0000000..f99d42a
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_posix.cc
@@ -0,0 +1,253 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "base/files/file_util.h"
+#include "base/numerics/checked_math.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+namespace {
+
+struct ScopedPathUnlinkerTraits {
+  static const FilePath* InvalidValue() { return nullptr; }
+
+  static void Free(const FilePath* path) {
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+using ScopedPathUnlinker =
+    ScopedGeneric<const FilePath*, ScopedPathUnlinkerTraits>;
+
+}  // namespace
+
+ScopedFDPair::ScopedFDPair() = default;
+
+ScopedFDPair::ScopedFDPair(ScopedFDPair&&) = default;
+
+ScopedFDPair& ScopedFDPair::operator=(ScopedFDPair&&) = default;
+
+ScopedFDPair::~ScopedFDPair() = default;
+
+ScopedFDPair::ScopedFDPair(ScopedFD in_fd, ScopedFD in_readonly_fd)
+    : fd(std::move(in_fd)), readonly_fd(std::move(in_readonly_fd)) {}
+
+FDPair ScopedFDPair::get() const {
+  return {fd.get(), readonly_fd.get()};
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+    ScopedFDPair handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid) {
+  if (!handle.fd.is_valid())
+    return {};
+
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK(
+      CheckPlatformHandlePermissionsCorrespondToMode(handle.get(), mode, size));
+
+  switch (mode) {
+    case Mode::kReadOnly:
+    case Mode::kUnsafe:
+      if (handle.readonly_fd.is_valid()) {
+        handle.readonly_fd.reset();
+        DLOG(WARNING) << "Readonly handle shouldn't be valid for a "
+                         "non-writable memory region; closing";
+      }
+      break;
+    case Mode::kWritable:
+      if (!handle.readonly_fd.is_valid()) {
+        DLOG(ERROR)
+            << "Readonly handle must be valid for writable memory region";
+        return {};
+      }
+      break;
+    default:
+      DLOG(ERROR) << "Invalid permission mode: " << static_cast<int>(mode);
+      return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
+}
+
+FDPair PlatformSharedMemoryRegion::GetPlatformHandle() const {
+  return handle_.get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+  return handle_.fd.is_valid() &&
+         (mode_ == Mode::kWritable ? handle_.readonly_fd.is_valid() : true);
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() {
+  if (!IsValid())
+    return {};
+
+  CHECK_NE(mode_, Mode::kWritable)
+      << "Duplicating a writable shared memory region is prohibited";
+
+  ScopedFD duped_fd(HANDLE_EINTR(dup(handle_.fd.get())));
+  if (!duped_fd.is_valid()) {
+    DPLOG(ERROR) << "dup(" << handle_.fd.get() << ") failed";
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion({std::move(duped_fd), ScopedFD()}, mode_,
+                                    size_, guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+  if (!IsValid())
+    return false;
+
+  CHECK_EQ(mode_, Mode::kWritable)
+      << "Only writable shared memory region can be converted to read-only";
+
+  handle_.fd.reset(handle_.readonly_fd.release());
+  mode_ = Mode::kReadOnly;
+  return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+                                       size_t size,
+                                       void** memory,
+                                       size_t* mapped_size) {
+  if (!IsValid())
+    return false;
+
+  size_t end_byte;
+  if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+    return false;
+  }
+
+  bool write_allowed = mode_ != Mode::kReadOnly;
+  *memory = mmap(nullptr, size, PROT_READ | (write_allowed ? PROT_WRITE : 0),
+                 MAP_SHARED, handle_.fd.get(), offset);
+
+  bool mmap_succeeded = *memory && *memory != reinterpret_cast<void*>(-1);
+  if (!mmap_succeeded) {
+    DPLOG(ERROR) << "mmap " << handle_.fd.get() << " failed";
+    return false;
+  }
+
+  *mapped_size = size;
+  DCHECK_EQ(0U,
+            reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+  return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+                                                              size_t size) {
+#if defined(OS_NACL)
+  // Untrusted code can't create descriptors or handles.
+  return {};
+#else
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+                                     "lead to this region being non-modifiable";
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  // We don't use shm_open() API in order to support the --disable-dev-shm-usage
+  // flag.
+  FilePath directory;
+  if (!GetShmemTempDir(false /* executable */, &directory))
+    return {};
+
+  ScopedFD fd;
+  FilePath path;
+  fd.reset(CreateAndOpenFdForTemporaryFileInDir(directory, &path));
+
+  if (!fd.is_valid()) {
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    FilePath dir = path.DirName();
+    if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+      PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+      if (dir.value() == "/dev/shm") {
+        LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+                   << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
+      }
+    }
+    return {};
+  }
+
+  // Deleting the file prevents anyone else from mapping it in (making it
+  // private), and prevents the need for cleanup (once the last fd is
+  // closed, it is truly freed).
+  ScopedPathUnlinker path_unlinker(&path);
+
+  ScopedFD readonly_fd;
+  if (mode == Mode::kWritable) {
+    // Also open as readonly so that we can ConvertToReadOnly().
+    readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+    if (!readonly_fd.is_valid()) {
+      DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+      return {};
+    }
+  }
+
+  // Get current size.
+  struct stat stat = {};
+  if (fstat(fd.get(), &stat) != 0)
+    return {};
+  const size_t current_size = stat.st_size;
+  if (current_size != size) {
+    if (HANDLE_EINTR(ftruncate(fd.get(), size)) != 0)
+      return {};
+  }
+
+  if (readonly_fd.is_valid()) {
+    struct stat readonly_stat = {};
+    if (fstat(readonly_fd.get(), &readonly_stat))
+      NOTREACHED();
+
+    if (stat.st_dev != readonly_stat.st_dev ||
+        stat.st_ino != readonly_stat.st_ino) {
+      LOG(ERROR) << "Writable and read-only inodes don't match; bailing";
+      return {};
+    }
+  }
+
+  return PlatformSharedMemoryRegion({std::move(fd), std::move(readonly_fd)},
+                                    mode, size, UnguessableToken::Create());
+#endif  // !defined(OS_NACL)
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    ScopedFDPair handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid)
+    : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region_unittest.cc b/base/memory/platform_shared_memory_region_unittest.cc
new file mode 100644
index 0000000..025840d
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include "base/memory/shared_memory_mapping.h"
+#include "base/process/process_metrics.h"
+#include "base/sys_info.h"
+#include "base/test/gtest_util.h"
+#include "base/test/test_shared_memory_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach_vm.h>
+#endif
+
+namespace base {
+namespace subtle {
+
+const size_t kRegionSize = 1024;
+
+class PlatformSharedMemoryRegionTest : public ::testing::Test {
+ public:
+  SharedMemoryMapping MapAt(PlatformSharedMemoryRegion* region,
+                            off_t offset,
+                            size_t bytes) {
+    void* memory = nullptr;
+    size_t mapped_size = 0;
+    if (!region->MapAt(offset, bytes, &memory, &mapped_size))
+      return {};
+
+    return SharedMemoryMapping(memory, mapped_size, region->GetGUID());
+  }
+
+  void* GetMemory(SharedMemoryMapping* mapping) {
+    return mapping->raw_memory_ptr();
+  }
+};
+
+// Tests that a default constructed region is invalid and produces invalid
+// mappings.
+TEST_F(PlatformSharedMemoryRegionTest, DefaultConstructedRegionIsInvalid) {
+  PlatformSharedMemoryRegion region;
+  EXPECT_FALSE(region.IsValid());
+  SharedMemoryMapping mapping = MapAt(&region, 0, kRegionSize);
+  EXPECT_FALSE(mapping.IsValid());
+  PlatformSharedMemoryRegion duplicate = region.Duplicate();
+  EXPECT_FALSE(duplicate.IsValid());
+  EXPECT_FALSE(region.ConvertToReadOnly());
+}
+
+// Tests that creating a region of 0 size returns an invalid region.
+TEST_F(PlatformSharedMemoryRegionTest, CreateRegionOfZeroSizeIsInvalid) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(0);
+  EXPECT_FALSE(region.IsValid());
+
+  PlatformSharedMemoryRegion region2 =
+      PlatformSharedMemoryRegion::CreateUnsafe(0);
+  EXPECT_FALSE(region2.IsValid());
+}
+
+// Tests that creating a region of size bigger than the integer max value
+// returns an invalid region.
+TEST_F(PlatformSharedMemoryRegionTest, CreateTooLargeRegionIsInvalid) {
+  size_t too_large_region_size =
+      static_cast<size_t>(std::numeric_limits<int>::max()) + 1;
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(too_large_region_size);
+  EXPECT_FALSE(region.IsValid());
+
+  PlatformSharedMemoryRegion region2 =
+      PlatformSharedMemoryRegion::CreateUnsafe(too_large_region_size);
+  EXPECT_FALSE(region2.IsValid());
+}
+
+// Tests that the platform-specific handle converted to read-only cannot be used
+// to perform a writable mapping with low-level system APIs like mmap().
+TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyHandleIsNotWritable) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  EXPECT_TRUE(region.ConvertToReadOnly());
+  EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly);
+  EXPECT_TRUE(
+      CheckReadOnlyPlatformSharedMemoryRegionForTesting(std::move(region)));
+}
+
+// Tests that the PassPlatformHandle() call invalidates the region.
+TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterPass) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  ignore_result(region.PassPlatformHandle());
+  EXPECT_FALSE(region.IsValid());
+}
+
+// Tests that the region is invalid after move.
+TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterMove) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  PlatformSharedMemoryRegion moved_region = std::move(region);
+  EXPECT_FALSE(region.IsValid());
+  EXPECT_TRUE(moved_region.IsValid());
+}
+
+// Tests that calling Take() with the size parameter equal to zero returns an
+// invalid region.
+TEST_F(PlatformSharedMemoryRegionTest, TakeRegionOfZeroSizeIsInvalid) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
+      region.PassPlatformHandle(), region.GetMode(), 0, region.GetGUID());
+  EXPECT_FALSE(region2.IsValid());
+}
+
+// Tests that calling Take() with the size parameter bigger than the integer max
+// value returns an invalid region.
+TEST_F(PlatformSharedMemoryRegionTest, TakeTooLargeRegionIsInvalid) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
+      region.PassPlatformHandle(), region.GetMode(),
+      static_cast<size_t>(std::numeric_limits<int>::max()) + 1,
+      region.GetGUID());
+  EXPECT_FALSE(region2.IsValid());
+}
+
+// Tests that mapping bytes out of the region limits fails.
+TEST_F(PlatformSharedMemoryRegionTest, MapAtOutOfTheRegionLimitsTest) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  SharedMemoryMapping mapping = MapAt(&region, 0, region.GetSize() + 1);
+  EXPECT_FALSE(mapping.IsValid());
+}
+
+// Tests that mapping with a size and offset causing overflow fails.
+TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(
+          SysInfo::VMAllocationGranularity() * 2);
+  ASSERT_TRUE(region.IsValid());
+  size_t size = std::numeric_limits<size_t>::max();
+  size_t offset = SysInfo::VMAllocationGranularity();
+  // |size| + |offset| should be below the region size due to overflow but
+  // mapping a region with these parameters should be invalid.
+  EXPECT_LT(size + offset, region.GetSize());
+  SharedMemoryMapping mapping = MapAt(&region, offset, size);
+  EXPECT_FALSE(mapping.IsValid());
+}
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \
+    !defined(OS_MACOSX)
+// Tests that the second handle is closed after a conversion to read-only on
+// POSIX.
+TEST_F(PlatformSharedMemoryRegionTest,
+       ConvertToReadOnlyInvalidatesSecondHandle) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  ASSERT_TRUE(region.ConvertToReadOnly());
+  FDPair fds = region.GetPlatformHandle();
+  EXPECT_LT(fds.readonly_fd, 0);
+}
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Tests that protection bits are set correctly for read-only region on MacOS.
+TEST_F(PlatformSharedMemoryRegionTest, MapCurrentAndMaxProtectionSetCorrectly) {
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  ASSERT_TRUE(region.ConvertToReadOnly());
+  SharedMemoryMapping ro_mapping = MapAt(&region, 0, kRegionSize);
+  ASSERT_TRUE(ro_mapping.IsValid());
+
+  vm_region_basic_info_64 basic_info;
+  mach_vm_size_t dummy_size = 0;
+  void* temp_addr = GetMemory(&ro_mapping);
+  MachVMRegionResult result = GetBasicInfo(
+      mach_task_self(), &dummy_size,
+      reinterpret_cast<mach_vm_address_t*>(&temp_addr), &basic_info);
+  EXPECT_EQ(result, MachVMRegionResult::Success);
+  EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ);
+  EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ);
+}
+#endif
+
+// Tests that it's impossible to create read-only platform shared memory region.
+TEST_F(PlatformSharedMemoryRegionTest, CreateReadOnlyRegionDeathTest) {
+#ifdef OFFICIAL_BUILD
+  // The official build does not print the reason a CHECK failed.
+  const char kErrorRegex[] = "";
+#else
+  const char kErrorRegex[] =
+      "Creating a region in read-only mode will lead to this region being "
+      "non-modifiable";
+#endif
+  EXPECT_DEATH_IF_SUPPORTED(
+      PlatformSharedMemoryRegion::Create(
+          PlatformSharedMemoryRegion::Mode::kReadOnly, kRegionSize),
+      kErrorRegex);
+}
+
+// Tests that it's prohibited to duplicate a writable region.
+TEST_F(PlatformSharedMemoryRegionTest, DuplicateWritableRegionDeathTest) {
+#ifdef OFFICIAL_BUILD
+  const char kErrorRegex[] = "";
+#else
+  const char kErrorRegex[] =
+      "Duplicating a writable shared memory region is prohibited";
+#endif
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  EXPECT_DEATH_IF_SUPPORTED(region.Duplicate(), kErrorRegex);
+}
+
+// Tests that it's prohibited to convert an unsafe region to read-only.
+TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToReadOnlyDeathTest) {
+#ifdef OFFICIAL_BUILD
+  const char kErrorRegex[] = "";
+#else
+  const char kErrorRegex[] =
+      "Only writable shared memory region can be converted to read-only";
+#endif
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
+}
+
+// Tests that it's prohibited to convert a read-only region to read-only.
+TEST_F(PlatformSharedMemoryRegionTest,
+       ReadOnlyRegionConvertToReadOnlyDeathTest) {
+#ifdef OFFICIAL_BUILD
+  const char kErrorRegex[] = "";
+#else
+  const char kErrorRegex[] =
+      "Only writable shared memory region can be converted to read-only";
+#endif
+  PlatformSharedMemoryRegion region =
+      PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  EXPECT_TRUE(region.ConvertToReadOnly());
+  EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
+}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/platform_shared_memory_region_win.cc b/base/memory/platform_shared_memory_region_win.cc
new file mode 100644
index 0000000..629e187
--- /dev/null
+++ b/base/memory/platform_shared_memory_region_win.cc
@@ -0,0 +1,316 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <aclapi.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/bits.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/checked_math.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace subtle {
+
+namespace {
+
+// Errors that can occur during Shared Memory construction.
+// These match tools/metrics/histograms/histograms.xml.
+// This enum is append-only.
+enum CreateError {
+  SUCCESS = 0,
+  SIZE_ZERO = 1,
+  SIZE_TOO_LARGE = 2,
+  INITIALIZE_ACL_FAILURE = 3,
+  INITIALIZE_SECURITY_DESC_FAILURE = 4,
+  SET_SECURITY_DESC_FAILURE = 5,
+  CREATE_FILE_MAPPING_FAILURE = 6,
+  REDUCE_PERMISSIONS_FAILURE = 7,
+  ALREADY_EXISTS = 8,
+  CREATE_ERROR_LAST = ALREADY_EXISTS
+};
+
+// Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
+// if there is no associated Windows error.
+void LogError(CreateError error, DWORD winerror) {
+  UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error,
+                            CREATE_ERROR_LAST + 1);
+  static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
+  if (winerror != ERROR_SUCCESS)
+    UmaHistogramSparse("SharedMemory.CreateWinError", winerror);
+}
+
+typedef enum _SECTION_INFORMATION_CLASS {
+  SectionBasicInformation,
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+  PVOID BaseAddress;
+  ULONG Attributes;
+  LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef ULONG(__stdcall* NtQuerySectionType)(
+    HANDLE SectionHandle,
+    SECTION_INFORMATION_CLASS SectionInformationClass,
+    PVOID SectionInformation,
+    ULONG SectionInformationLength,
+    PULONG ResultLength);
+
+// Returns the length of the memory section starting at the supplied address.
+size_t GetMemorySectionSize(void* address) {
+  MEMORY_BASIC_INFORMATION memory_info;
+  if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
+    return 0;
+  return memory_info.RegionSize -
+         (static_cast<char*>(address) -
+          static_cast<char*>(memory_info.AllocationBase));
+}
+
+// Checks if the section object is safe to map. At the moment this just means
+// it's not an image section.
+bool IsSectionSafeToMap(HANDLE handle) {
+  static NtQuerySectionType nt_query_section_func =
+      reinterpret_cast<NtQuerySectionType>(
+          ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
+  DCHECK(nt_query_section_func);
+
+  // The handle must have SECTION_QUERY access for this to succeed.
+  SECTION_BASIC_INFORMATION basic_information = {};
+  ULONG status =
+      nt_query_section_func(handle, SectionBasicInformation, &basic_information,
+                            sizeof(basic_information), nullptr);
+  if (status)
+    return false;
+  return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
+}
+
+// Returns a HANDLE on success and |nullptr| on failure.
+// This function is similar to CreateFileMapping, but removes the permissions
+// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
+//
+// A newly created file mapping has two sets of permissions. It has access
+// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
+// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). The Chrome sandbox
+// prevents HANDLEs with the WRITE_DAC permission from being duplicated into
+// unprivileged processes.
+//
+// In order to remove the access control permissions, after being created the
+// handle is duplicated with only the file access permissions.
+HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
+                                               size_t rounded_size,
+                                               LPCWSTR name) {
+  HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
+                               static_cast<DWORD>(rounded_size), name);
+  if (!h) {
+    LogError(CREATE_FILE_MAPPING_FAILURE, GetLastError());
+    return nullptr;
+  }
+
+  HANDLE h2;
+  ProcessHandle process = GetCurrentProcess();
+  BOOL success = ::DuplicateHandle(
+      process, h, process, &h2, FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY,
+      FALSE, 0);
+  BOOL rv = ::CloseHandle(h);
+  DCHECK(rv);
+
+  if (!success) {
+    LogError(REDUCE_PERMISSIONS_FAILURE, GetLastError());
+    return nullptr;
+  }
+
+  return h2;
+}
+
+}  // namespace
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+    win::ScopedHandle handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid) {
+  if (!handle.IsValid())
+    return {};
+
+  if (size == 0)
+    return {};
+
+  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return {};
+
+  if (!IsSectionSafeToMap(handle.Get()))
+    return {};
+
+  CHECK(
+      CheckPlatformHandlePermissionsCorrespondToMode(handle.Get(), mode, size));
+
+  return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
+}
+
+HANDLE PlatformSharedMemoryRegion::GetPlatformHandle() const {
+  return handle_.Get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+  return handle_.IsValid();
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() {
+  if (!IsValid())
+    return {};
+
+  CHECK_NE(mode_, Mode::kWritable)
+      << "Duplicating a writable shared memory region is prohibited";
+
+  HANDLE duped_handle;
+  ProcessHandle process = GetCurrentProcess();
+  BOOL success =
+      ::DuplicateHandle(process, handle_.Get(), process, &duped_handle, 0,
+                        FALSE, DUPLICATE_SAME_ACCESS);
+  if (!success)
+    return {};
+
+  return PlatformSharedMemoryRegion(win::ScopedHandle(duped_handle), mode_,
+                                    size_, guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+  if (!IsValid())
+    return false;
+
+  CHECK_EQ(mode_, Mode::kWritable)
+      << "Only writable shared memory region can be converted to read-only";
+
+  win::ScopedHandle handle_copy(handle_.Take());
+
+  HANDLE duped_handle;
+  ProcessHandle process = GetCurrentProcess();
+  BOOL success =
+      ::DuplicateHandle(process, handle_copy.Get(), process, &duped_handle,
+                        FILE_MAP_READ | SECTION_QUERY, FALSE, 0);
+  if (!success)
+    return false;
+
+  handle_.Set(duped_handle);
+  mode_ = Mode::kReadOnly;
+  return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+                                       size_t size,
+                                       void** memory,
+                                       size_t* mapped_size) {
+  if (!IsValid())
+    return false;
+
+  size_t end_byte;
+  if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+    return false;
+  }
+
+  bool write_allowed = mode_ != Mode::kReadOnly;
+  // Try to map the shared memory. On the first failure, release any reserved
+  // address space for a single entry.
+  for (int i = 0; i < 2; ++i) {
+    *memory = MapViewOfFile(
+        handle_.Get(), FILE_MAP_READ | (write_allowed ? FILE_MAP_WRITE : 0),
+        static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), size);
+    if (*memory)
+      break;
+    ReleaseReservation();
+  }
+  if (!*memory) {
+    DPLOG(ERROR) << "Failed executing MapViewOfFile";
+    return false;
+  }
+
+  *mapped_size = GetMemorySectionSize(*memory);
+  DCHECK_EQ(0U,
+            reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+  return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+                                                              size_t size) {
+  // TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
+  // per mapping on average.
+  static const size_t kSectionSize = 65536;
+  if (size == 0) {
+    LogError(SIZE_ZERO, 0);
+    return {};
+  }
+
+  size_t rounded_size = bits::Align(size, kSectionSize);
+  if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    LogError(SIZE_TOO_LARGE, 0);
+    return {};
+  }
+
+  CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+                                     "lead to this region being non-modifiable";
+
+  // Add an empty DACL to enforce anonymous read-only sections.
+  ACL dacl;
+  SECURITY_DESCRIPTOR sd;
+  if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
+    LogError(INITIALIZE_ACL_FAILURE, GetLastError());
+    return {};
+  }
+  if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
+    LogError(INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
+    return {};
+  }
+  if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
+    LogError(SET_SECURITY_DESC_FAILURE, GetLastError());
+    return {};
+  }
+
+  // Windows ignores DACLs on unnamed shared section. Generate a random name in
+  // order to be able to enforce read-only.
+  uint64_t rand_values[4];
+  RandBytes(&rand_values, sizeof(rand_values));
+  string16 name =
+      StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx", rand_values[0],
+                   rand_values[1], rand_values[2], rand_values[3]);
+
+  SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE};
+  // Ask for the file mapping with reduced permisions to avoid passing the
+  // access control permissions granted by default into unpriviledged process.
+  HANDLE h =
+      CreateFileMappingWithReducedPermissions(&sa, rounded_size, name.c_str());
+  if (h == nullptr) {
+    // The error is logged within CreateFileMappingWithReducedPermissions().
+    return {};
+  }
+
+  win::ScopedHandle scoped_h(h);
+  // Check if the shared memory pre-exists.
+  if (GetLastError() == ERROR_ALREADY_EXISTS) {
+    LogError(ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
+    return {};
+  }
+
+  return PlatformSharedMemoryRegion(std::move(scoped_h), mode, rounded_size,
+                                    UnguessableToken::Create());
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+    win::ScopedHandle handle,
+    Mode mode,
+    size_t size,
+    const UnguessableToken& guid)
+    : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/base/memory/read_only_shared_memory_region.cc b/base/memory/read_only_shared_memory_region.cc
new file mode 100644
index 0000000..dd9f7a6
--- /dev/null
+++ b/base/memory/read_only_shared_memory_region.cc
@@ -0,0 +1,93 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/read_only_shared_memory_region.h"
+
+#include <utility>
+
+#include "base/memory/shared_memory.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// static
+MappedReadOnlyRegion ReadOnlySharedMemoryRegion::Create(size_t size) {
+  subtle::PlatformSharedMemoryRegion handle =
+      subtle::PlatformSharedMemoryRegion::CreateWritable(size);
+  if (!handle.IsValid())
+    return {};
+
+  void* memory_ptr = nullptr;
+  size_t mapped_size = 0;
+  if (!handle.MapAt(0, handle.GetSize(), &memory_ptr, &mapped_size))
+    return {};
+
+  WritableSharedMemoryMapping mapping(memory_ptr, mapped_size,
+                                      handle.GetGUID());
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  handle.ConvertToReadOnly(memory_ptr);
+#else
+  handle.ConvertToReadOnly();
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+  ReadOnlySharedMemoryRegion region(std::move(handle));
+
+  if (!region.IsValid())
+    return {};
+
+  return {std::move(region), std::move(mapping)};
+}
+
+// static
+ReadOnlySharedMemoryRegion ReadOnlySharedMemoryRegion::Deserialize(
+    subtle::PlatformSharedMemoryRegion handle) {
+  return ReadOnlySharedMemoryRegion(std::move(handle));
+}
+
+// static
+subtle::PlatformSharedMemoryRegion
+ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
+    ReadOnlySharedMemoryRegion region) {
+  return std::move(region.handle_);
+}
+
+ReadOnlySharedMemoryRegion::ReadOnlySharedMemoryRegion() = default;
+ReadOnlySharedMemoryRegion::ReadOnlySharedMemoryRegion(
+    ReadOnlySharedMemoryRegion&& region) = default;
+ReadOnlySharedMemoryRegion& ReadOnlySharedMemoryRegion::operator=(
+    ReadOnlySharedMemoryRegion&& region) = default;
+ReadOnlySharedMemoryRegion::~ReadOnlySharedMemoryRegion() = default;
+
+ReadOnlySharedMemoryRegion ReadOnlySharedMemoryRegion::Duplicate() {
+  return ReadOnlySharedMemoryRegion(handle_.Duplicate());
+}
+
+ReadOnlySharedMemoryMapping ReadOnlySharedMemoryRegion::Map() {
+  return MapAt(0, handle_.GetSize());
+}
+
+ReadOnlySharedMemoryMapping ReadOnlySharedMemoryRegion::MapAt(off_t offset,
+                                                              size_t size) {
+  if (!IsValid())
+    return {};
+
+  void* memory = nullptr;
+  size_t mapped_size = 0;
+  if (!handle_.MapAt(offset, size, &memory, &mapped_size))
+    return {};
+
+  return ReadOnlySharedMemoryMapping(memory, mapped_size, handle_.GetGUID());
+}
+
+bool ReadOnlySharedMemoryRegion::IsValid() {
+  return handle_.IsValid();
+}
+
+ReadOnlySharedMemoryRegion::ReadOnlySharedMemoryRegion(
+    subtle::PlatformSharedMemoryRegion handle)
+    : handle_(std::move(handle)) {
+  CHECK_EQ(handle_.GetMode(),
+           subtle::PlatformSharedMemoryRegion::Mode::kReadOnly);
+}
+
+}  // namespace base
diff --git a/base/memory/read_only_shared_memory_region.h b/base/memory/read_only_shared_memory_region.h
new file mode 100644
index 0000000..bccf42a
--- /dev/null
+++ b/base/memory/read_only_shared_memory_region.h
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_READ_ONLY_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_READ_ONLY_SHARED_MEMORY_REGION_H_
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
+
+namespace base {
+
+struct MappedReadOnlyRegion;
+
+// Scoped move-only handle to a region of platform shared memory. The instance
+// owns the platform handle it wraps. Mappings created by this region are
+// read-only. These mappings remain valid even after the region handle is moved
+// or destroyed.
+class BASE_EXPORT ReadOnlySharedMemoryRegion {
+ public:
+  using MappingType = ReadOnlySharedMemoryMapping;
+  // Creates a new ReadOnlySharedMemoryRegion instance of a given size along
+  // with the WritableSharedMemoryMapping which provides the only way to modify
+  // the content of the newly created region.
+  //
+  // This means that the caller's process is the only process that can modify
+  // the region content. If you need to pass write access to another process,
+  // consider using WritableSharedMemoryRegion or UnsafeSharedMemoryRegion.
+  static MappedReadOnlyRegion Create(size_t size);
+
+  // Returns a ReadOnlySharedMemoryRegion built from a platform-specific handle
+  // that was taken from another ReadOnlySharedMemoryRegion instance. Returns an
+  // invalid region iff the |handle| is invalid. CHECK-fails if the |handle|
+  // isn't read-only.
+  // This should be used only by the code passing handles across process
+  // boundaries.
+  static ReadOnlySharedMemoryRegion Deserialize(
+      subtle::PlatformSharedMemoryRegion handle);
+
+  // Extracts a platform handle from the region. Ownership is transferred to the
+  // returned region object.
+  // This should be used only for sending the handle from the current process to
+  // another.
+  static subtle::PlatformSharedMemoryRegion TakeHandleForSerialization(
+      ReadOnlySharedMemoryRegion region);
+
+  // Default constructor initializes an invalid instance.
+  ReadOnlySharedMemoryRegion();
+
+  // Move operations are allowed.
+  ReadOnlySharedMemoryRegion(ReadOnlySharedMemoryRegion&&);
+  ReadOnlySharedMemoryRegion& operator=(ReadOnlySharedMemoryRegion&&);
+
+  // Destructor closes shared memory region if valid.
+  // All created mappings will remain valid.
+  ~ReadOnlySharedMemoryRegion();
+
+  // Duplicates the underlying platform handle and creates a new
+  // ReadOnlySharedMemoryRegion instance that owns this handle. Returns a valid
+  // ReadOnlySharedMemoryRegion on success, invalid otherwise. The current
+  // region instance remains valid in any case.
+  ReadOnlySharedMemoryRegion Duplicate();
+
+  // Maps the shared memory region into the caller's address space with
+  // read-only access. The mapped address is guaranteed to have an alignment of
+  // at least |subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment|.
+  // Returns a valid ReadOnlySharedMemoryMapping instance on success, invalid
+  // otherwise.
+  ReadOnlySharedMemoryMapping Map();
+
+  // Same as above, but maps only |size| bytes of the shared memory region
+  // starting with the given |offset|. |offset| must be aligned to value of
+  // |SysInfo::VMAllocationGranularity()|. Returns an invalid mapping if
+  // requested bytes are out of the region limits.
+  ReadOnlySharedMemoryMapping MapAt(off_t offset, size_t size);
+
+  // Whether the underlying platform handle is valid.
+  bool IsValid();
+
+  // Returns the maximum mapping size that can be created from this region.
+  size_t GetSize() {
+    DCHECK(IsValid());
+    return handle_.GetSize();
+  }
+
+ private:
+  explicit ReadOnlySharedMemoryRegion(
+      subtle::PlatformSharedMemoryRegion handle);
+
+  subtle::PlatformSharedMemoryRegion handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlySharedMemoryRegion);
+};
+
+// Helper struct for return value of ReadOnlySharedMemoryRegion::Create().
+struct MappedReadOnlyRegion {
+  ReadOnlySharedMemoryRegion region;
+  WritableSharedMemoryMapping mapping;
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_READ_ONLY_SHARED_MEMORY_REGION_H_
diff --git a/base/memory/shared_memory_mapping.cc b/base/memory/shared_memory_mapping.cc
new file mode 100644
index 0000000..b034fc1
--- /dev/null
+++ b/base/memory/shared_memory_mapping.cc
@@ -0,0 +1,108 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory_mapping.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/shared_memory_tracker.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
+#if defined(OS_WIN)
+#include <aclapi.h>
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach_vm.h>
+#include "base/mac/mach_logging.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <zircon/process.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#endif
+
+namespace base {
+
+SharedMemoryMapping::SharedMemoryMapping() = default;
+
+SharedMemoryMapping::SharedMemoryMapping(SharedMemoryMapping&& mapping)
+    : memory_(mapping.memory_), size_(mapping.size_), guid_(mapping.guid_) {
+  mapping.memory_ = nullptr;
+}
+
+SharedMemoryMapping& SharedMemoryMapping::operator=(
+    SharedMemoryMapping&& mapping) {
+  Unmap();
+  memory_ = mapping.memory_;
+  size_ = mapping.size_;
+  guid_ = mapping.guid_;
+  mapping.memory_ = nullptr;
+  return *this;
+}
+
+SharedMemoryMapping::~SharedMemoryMapping() {
+  Unmap();
+}
+
+SharedMemoryMapping::SharedMemoryMapping(void* memory,
+                                         size_t size,
+                                         const UnguessableToken& guid)
+    : memory_(memory), size_(size), guid_(guid) {
+  SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+}
+
+void SharedMemoryMapping::Unmap() {
+  if (!IsValid())
+    return;
+
+  SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+#if defined(OS_WIN)
+  if (!UnmapViewOfFile(memory_))
+    DPLOG(ERROR) << "UnmapViewOfFile";
+#elif defined(OS_FUCHSIA)
+  uintptr_t addr = reinterpret_cast<uintptr_t>(memory_);
+  zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(), addr, size_);
+  DLOG_IF(ERROR, status != ZX_OK)
+      << "zx_vmar_unmap failed: " << zx_status_get_string(status);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  kern_return_t kr = mach_vm_deallocate(
+      mach_task_self(), reinterpret_cast<mach_vm_address_t>(memory_), size_);
+  MACH_DLOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_vm_deallocate";
+#else
+  if (munmap(memory_, size_) < 0)
+    DPLOG(ERROR) << "munmap";
+#endif
+}
+
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping() = default;
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
+    ReadOnlySharedMemoryMapping&&) = default;
+ReadOnlySharedMemoryMapping& ReadOnlySharedMemoryMapping::operator=(
+    ReadOnlySharedMemoryMapping&&) = default;
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
+    void* address,
+    size_t size,
+    const UnguessableToken& guid)
+    : SharedMemoryMapping(address, size, guid) {}
+
+WritableSharedMemoryMapping::WritableSharedMemoryMapping() = default;
+WritableSharedMemoryMapping::WritableSharedMemoryMapping(
+    WritableSharedMemoryMapping&&) = default;
+WritableSharedMemoryMapping& WritableSharedMemoryMapping::operator=(
+    WritableSharedMemoryMapping&&) = default;
+WritableSharedMemoryMapping::WritableSharedMemoryMapping(
+    void* address,
+    size_t size,
+    const UnguessableToken& guid)
+    : SharedMemoryMapping(address, size, guid) {}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_mapping.h b/base/memory/shared_memory_mapping.h
new file mode 100644
index 0000000..35b519c
--- /dev/null
+++ b/base/memory/shared_memory_mapping.h
@@ -0,0 +1,128 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
+#define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
+
+#include <cstddef>
+
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+
+namespace base {
+
+namespace subtle {
+class PlatformSharedMemoryRegion;
+class PlatformSharedMemoryRegionTest;
+}  // namespace subtle
+
+// Base class for scoped handles to a shared memory mapping created from a
+// shared memory region. Created shared memory mappings remain valid even if the
+// creator region is transferred or destroyed.
+//
+// Each mapping has an UnguessableToken that identifies the shared memory region
+// it was created from. This is used for memory metrics, to avoid overcounting
+// shared memory.
+class BASE_EXPORT SharedMemoryMapping {
+ public:
+  // Default constructor initializes an invalid instance.
+  SharedMemoryMapping();
+
+  // Move operations are allowed.
+  SharedMemoryMapping(SharedMemoryMapping&& mapping);
+  SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping);
+
+  // Unmaps the region if the mapping is valid.
+  virtual ~SharedMemoryMapping();
+
+  // Returns true iff the mapping is valid. False means there is no
+  // corresponding area of memory.
+  bool IsValid() const { return memory_ != nullptr; }
+
+  // Returns the size of the mapping in bytes. This is page-aligned. This is
+  // undefined for invalid instances.
+  size_t size() const {
+    DCHECK(IsValid());
+    return size_;
+  }
+
+  // Returns 128-bit GUID of the region this mapping belongs to.
+  const UnguessableToken& guid() const {
+    DCHECK(IsValid());
+    return guid_;
+  }
+
+ protected:
+  SharedMemoryMapping(void* address, size_t size, const UnguessableToken& guid);
+  void* raw_memory_ptr() const { return memory_; }
+
+ private:
+  friend class subtle::PlatformSharedMemoryRegionTest;
+  friend class SharedMemoryTracker;
+
+  void Unmap();
+
+  void* memory_ = nullptr;
+  size_t size_ = 0;
+  UnguessableToken guid_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryMapping);
+};
+
+// Class modeling a read-only mapping of a shared memory region into the
+// current process' address space. This is created by ReadOnlySharedMemoryRegion
+// instances.
+class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
+ public:
+  // Default constructor initializes an invalid instance.
+  ReadOnlySharedMemoryMapping();
+
+  // Move operations are allowed.
+  ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&);
+  ReadOnlySharedMemoryMapping& operator=(ReadOnlySharedMemoryMapping&&);
+
+  // Returns the base address of the mapping. This is read-only memory. This is
+  // page-aligned. This is nullptr for invalid instances.
+  const void* memory() const { return raw_memory_ptr(); }
+
+ private:
+  friend class ReadOnlySharedMemoryRegion;
+  ReadOnlySharedMemoryMapping(void* address,
+                              size_t size,
+                              const UnguessableToken& guid);
+
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlySharedMemoryMapping);
+};
+
+// Class modeling a writable mapping of a shared memory region into the
+// current process' address space. This is created by *SharedMemoryRegion
+// instances.
+class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
+ public:
+  // Default constructor initializes an invalid instance.
+  WritableSharedMemoryMapping();
+
+  // Move operations are allowed.
+  WritableSharedMemoryMapping(WritableSharedMemoryMapping&&);
+  WritableSharedMemoryMapping& operator=(WritableSharedMemoryMapping&&);
+
+  // Returns the base address of the mapping. This is writable memory. This is
+  // page-aligned. This is nullptr for invalid instances.
+  void* memory() const { return raw_memory_ptr(); }
+
+ private:
+  friend class subtle::PlatformSharedMemoryRegion;
+  friend class ReadOnlySharedMemoryRegion;
+  friend class WritableSharedMemoryRegion;
+  friend class UnsafeSharedMemoryRegion;
+  WritableSharedMemoryMapping(void* address,
+                              size_t size,
+                              const UnguessableToken& guid);
+
+  DISALLOW_COPY_AND_ASSIGN(WritableSharedMemoryMapping);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
diff --git a/base/memory/shared_memory_region_unittest.cc b/base/memory/shared_memory_region_unittest.cc
new file mode 100644
index 0000000..f85a7c3
--- /dev/null
+++ b/base/memory/shared_memory_region_unittest.cc
@@ -0,0 +1,292 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/unsafe_shared_memory_region.h"
+#include "base/memory/writable_shared_memory_region.h"
+#include "base/sys_info.h"
+#include "base/test/test_shared_memory_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+const size_t kRegionSize = 1024;
+
+bool IsMemoryFilledWithByte(const void* memory, size_t size, char byte) {
+  const char* start_ptr = static_cast<const char*>(memory);
+  const char* end_ptr = start_ptr + size;
+  for (const char* ptr = start_ptr; ptr < end_ptr; ++ptr) {
+    if (*ptr != byte)
+      return false;
+  }
+
+  return true;
+}
+
+template <typename SharedMemoryRegionType>
+class SharedMemoryRegionTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    std::tie(region_, rw_mapping_) = CreateWithMapping(kRegionSize);
+    ASSERT_TRUE(region_.IsValid());
+    ASSERT_TRUE(rw_mapping_.IsValid());
+    memset(rw_mapping_.memory(), 'G', kRegionSize);
+    EXPECT_TRUE(IsMemoryFilledWithByte(rw_mapping_.memory(), kRegionSize, 'G'));
+  }
+
+  static std::pair<SharedMemoryRegionType, WritableSharedMemoryMapping>
+  CreateWithMapping(size_t size) {
+    SharedMemoryRegionType region = SharedMemoryRegionType::Create(size);
+    WritableSharedMemoryMapping mapping = region.Map();
+    return {std::move(region), std::move(mapping)};
+  }
+
+ protected:
+  SharedMemoryRegionType region_;
+  WritableSharedMemoryMapping rw_mapping_;
+};
+
+// Template specialization of SharedMemoryRegionTest<>::CreateWithMapping() for
+// the ReadOnlySharedMemoryRegion. We need this because
+// ReadOnlySharedMemoryRegion::Create() has a different return type.
+template <>
+std::pair<ReadOnlySharedMemoryRegion, WritableSharedMemoryMapping>
+SharedMemoryRegionTest<ReadOnlySharedMemoryRegion>::CreateWithMapping(
+    size_t size) {
+  MappedReadOnlyRegion mapped_region = ReadOnlySharedMemoryRegion::Create(size);
+  return {std::move(mapped_region.region), std::move(mapped_region.mapping)};
+}
+
+typedef ::testing::Types<WritableSharedMemoryRegion,
+                         UnsafeSharedMemoryRegion,
+                         ReadOnlySharedMemoryRegion>
+    AllRegionTypes;
+TYPED_TEST_CASE(SharedMemoryRegionTest, AllRegionTypes);
+
+TYPED_TEST(SharedMemoryRegionTest, NonValidRegion) {
+  TypeParam region;
+  EXPECT_FALSE(region.IsValid());
+  // We shouldn't crash on Map but should return an invalid mapping.
+  typename TypeParam::MappingType mapping = region.Map();
+  EXPECT_FALSE(mapping.IsValid());
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MoveRegion) {
+  TypeParam moved_region = std::move(this->region_);
+  EXPECT_FALSE(this->region_.IsValid());
+  ASSERT_TRUE(moved_region.IsValid());
+
+  // Check that moved region maps correctly.
+  typename TypeParam::MappingType mapping = moved_region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
+  EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
+            0);
+
+  // Verify that the second mapping reflects changes in the first.
+  memset(this->rw_mapping_.memory(), '#', kRegionSize);
+  EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
+            0);
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MappingValidAfterClose) {
+  // Check the mapping is still valid after the region is closed.
+  this->region_ = TypeParam();
+  EXPECT_FALSE(this->region_.IsValid());
+  ASSERT_TRUE(this->rw_mapping_.IsValid());
+  EXPECT_TRUE(
+      IsMemoryFilledWithByte(this->rw_mapping_.memory(), kRegionSize, 'G'));
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapTwice) {
+  // The second mapping is either writable or read-only.
+  typename TypeParam::MappingType mapping = this->region_.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
+  EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
+            0);
+
+  // Verify that the second mapping reflects changes in the first.
+  memset(this->rw_mapping_.memory(), '#', kRegionSize);
+  EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
+            0);
+
+  // Close the region and unmap the first memory segment, verify the second
+  // still has the right data.
+  this->region_ = TypeParam();
+  this->rw_mapping_ = WritableSharedMemoryMapping();
+  EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, '#'));
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapUnmapMap) {
+  this->rw_mapping_ = WritableSharedMemoryMapping();
+
+  typename TypeParam::MappingType mapping = this->region_.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
+}
+
+TYPED_TEST(SharedMemoryRegionTest, SerializeAndDeserialize) {
+  subtle::PlatformSharedMemoryRegion platform_region =
+      TypeParam::TakeHandleForSerialization(std::move(this->region_));
+  EXPECT_EQ(platform_region.GetGUID(), this->rw_mapping_.guid());
+  TypeParam region = TypeParam::Deserialize(std::move(platform_region));
+  EXPECT_TRUE(region.IsValid());
+  EXPECT_FALSE(this->region_.IsValid());
+  typename TypeParam::MappingType mapping = region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
+
+  // Verify that the second mapping reflects changes in the first.
+  memset(this->rw_mapping_.memory(), '#', kRegionSize);
+  EXPECT_EQ(memcmp(this->rw_mapping_.memory(), mapping.memory(), kRegionSize),
+            0);
+}
+
+// Map() will return addresses which are aligned to the platform page size, this
+// varies from platform to platform though.  Since we'd like to advertise a
+// minimum alignment that callers can count on, test for it here.
+TYPED_TEST(SharedMemoryRegionTest, MapMinimumAlignment) {
+  EXPECT_EQ(0U,
+            reinterpret_cast<uintptr_t>(this->rw_mapping_.memory()) &
+                (subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment - 1));
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapGranularity) {
+  EXPECT_GE(this->rw_mapping_.size(), kRegionSize);
+  EXPECT_LT(this->rw_mapping_.size(),
+            kRegionSize + SysInfo::VMAllocationGranularity());
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapAt) {
+  const size_t kPageSize = SysInfo::VMAllocationGranularity();
+  ASSERT_TRUE(kPageSize >= sizeof(uint32_t));
+  ASSERT_EQ(kPageSize % sizeof(uint32_t), 0U);
+  const size_t kDataSize = kPageSize * 2;
+  const size_t kCount = kDataSize / sizeof(uint32_t);
+
+  TypeParam region;
+  WritableSharedMemoryMapping rw_mapping;
+  std::tie(region, rw_mapping) = TestFixture::CreateWithMapping(kDataSize);
+  ASSERT_TRUE(region.IsValid());
+  ASSERT_TRUE(rw_mapping.IsValid());
+  uint32_t* ptr = static_cast<uint32_t*>(rw_mapping.memory());
+
+  for (size_t i = 0; i < kCount; ++i)
+    ptr[i] = i;
+
+  rw_mapping = WritableSharedMemoryMapping();
+  off_t bytes_offset = kPageSize;
+  typename TypeParam::MappingType mapping =
+      region.MapAt(bytes_offset, kDataSize - bytes_offset);
+  ASSERT_TRUE(mapping.IsValid());
+
+  off_t int_offset = bytes_offset / sizeof(uint32_t);
+  const uint32_t* ptr2 = static_cast<const uint32_t*>(mapping.memory());
+  for (size_t i = int_offset; i < kCount; ++i) {
+    EXPECT_EQ(ptr2[i - int_offset], i);
+  }
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapAtNotAlignedOffsetFails) {
+  const size_t kDataSize = SysInfo::VMAllocationGranularity();
+
+  TypeParam region;
+  WritableSharedMemoryMapping rw_mapping;
+  std::tie(region, rw_mapping) = TestFixture::CreateWithMapping(kDataSize);
+  ASSERT_TRUE(region.IsValid());
+  ASSERT_TRUE(rw_mapping.IsValid());
+  off_t offset = kDataSize / 2;
+  typename TypeParam::MappingType mapping =
+      region.MapAt(offset, kDataSize - offset);
+  EXPECT_FALSE(mapping.IsValid());
+}
+
+TYPED_TEST(SharedMemoryRegionTest, MapMoreBytesThanRegionSizeFails) {
+  size_t region_real_size = this->region_.GetSize();
+  typename TypeParam::MappingType mapping =
+      this->region_.MapAt(0, region_real_size + 1);
+  EXPECT_FALSE(mapping.IsValid());
+}
+
+template <typename DuplicatableSharedMemoryRegion>
+class DuplicatableSharedMemoryRegionTest
+    : public SharedMemoryRegionTest<DuplicatableSharedMemoryRegion> {};
+
+typedef ::testing::Types<UnsafeSharedMemoryRegion, ReadOnlySharedMemoryRegion>
+    DuplicatableRegionTypes;
+TYPED_TEST_CASE(DuplicatableSharedMemoryRegionTest, DuplicatableRegionTypes);
+
+TYPED_TEST(DuplicatableSharedMemoryRegionTest, Duplicate) {
+  TypeParam dup_region = this->region_.Duplicate();
+  typename TypeParam::MappingType mapping = dup_region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  EXPECT_NE(this->rw_mapping_.memory(), mapping.memory());
+  EXPECT_EQ(this->rw_mapping_.guid(), mapping.guid());
+  EXPECT_TRUE(IsMemoryFilledWithByte(mapping.memory(), kRegionSize, 'G'));
+}
+
+class ReadOnlySharedMemoryRegionTest : public ::testing::Test {
+ public:
+  ReadOnlySharedMemoryRegion GetInitiallyReadOnlyRegion(size_t size) {
+    MappedReadOnlyRegion mapped_region =
+        ReadOnlySharedMemoryRegion::Create(size);
+    ReadOnlySharedMemoryRegion region = std::move(mapped_region.region);
+    return region;
+  }
+
+  ReadOnlySharedMemoryRegion GetConvertedToReadOnlyRegion(size_t size) {
+    WritableSharedMemoryRegion region =
+        WritableSharedMemoryRegion::Create(kRegionSize);
+    ReadOnlySharedMemoryRegion ro_region =
+        WritableSharedMemoryRegion::ConvertToReadOnly(std::move(region));
+    return ro_region;
+  }
+};
+
+TEST_F(ReadOnlySharedMemoryRegionTest,
+       InitiallyReadOnlyRegionCannotBeMappedAsWritable) {
+  ReadOnlySharedMemoryRegion region = GetInitiallyReadOnlyRegion(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+
+  EXPECT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+      ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
+          std::move(region))));
+}
+
+TEST_F(ReadOnlySharedMemoryRegionTest,
+       ConvertedToReadOnlyRegionCannotBeMappedAsWritable) {
+  ReadOnlySharedMemoryRegion region = GetConvertedToReadOnlyRegion(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+
+  EXPECT_TRUE(CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+      ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
+          std::move(region))));
+}
+
+TEST_F(ReadOnlySharedMemoryRegionTest,
+       InitiallyReadOnlyRegionProducedMappingWriteDeathTest) {
+  ReadOnlySharedMemoryRegion region = GetInitiallyReadOnlyRegion(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  ReadOnlySharedMemoryMapping mapping = region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  void* memory_ptr = const_cast<void*>(mapping.memory());
+  EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), "");
+}
+
+TEST_F(ReadOnlySharedMemoryRegionTest,
+       ConvertedToReadOnlyRegionProducedMappingWriteDeathTest) {
+  ReadOnlySharedMemoryRegion region = GetConvertedToReadOnlyRegion(kRegionSize);
+  ASSERT_TRUE(region.IsValid());
+  ReadOnlySharedMemoryMapping mapping = region.Map();
+  ASSERT_TRUE(mapping.IsValid());
+  void* memory_ptr = const_cast<void*>(mapping.memory());
+  EXPECT_DEATH_IF_SUPPORTED(memset(memory_ptr, 'G', kRegionSize), "");
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_tracker.cc b/base/memory/shared_memory_tracker.cc
index 2b82338..e1cf818 100644
--- a/base/memory/shared_memory_tracker.cc
+++ b/base/memory/shared_memory_tracker.cc
@@ -39,20 +39,80 @@
 SharedMemoryTracker::GetOrCreateSharedMemoryDump(
     const SharedMemory* shared_memory,
     trace_event::ProcessMemoryDump* pmd) {
-  const std::string dump_name =
-      GetDumpNameForTracing(shared_memory->mapped_id());
+  return GetOrCreateSharedMemoryDumpInternal(shared_memory->memory(),
+                                             shared_memory->mapped_size(),
+                                             shared_memory->mapped_id(), pmd);
+}
+
+void SharedMemoryTracker::IncrementMemoryUsage(
+    const SharedMemory& shared_memory) {
+  AutoLock hold(usages_lock_);
+  DCHECK(usages_.find(shared_memory.memory()) == usages_.end());
+  usages_.emplace(shared_memory.memory(), UsageInfo(shared_memory.mapped_size(),
+                                                    shared_memory.mapped_id()));
+}
+
+void SharedMemoryTracker::IncrementMemoryUsage(
+    const SharedMemoryMapping& mapping) {
+  AutoLock hold(usages_lock_);
+  DCHECK(usages_.find(mapping.raw_memory_ptr()) == usages_.end());
+  usages_.emplace(mapping.raw_memory_ptr(),
+                  UsageInfo(mapping.size(), mapping.guid()));
+}
+
+void SharedMemoryTracker::DecrementMemoryUsage(
+    const SharedMemory& shared_memory) {
+  AutoLock hold(usages_lock_);
+  DCHECK(usages_.find(shared_memory.memory()) != usages_.end());
+  usages_.erase(shared_memory.memory());
+}
+
+void SharedMemoryTracker::DecrementMemoryUsage(
+    const SharedMemoryMapping& mapping) {
+  AutoLock hold(usages_lock_);
+  DCHECK(usages_.find(mapping.raw_memory_ptr()) != usages_.end());
+  usages_.erase(mapping.raw_memory_ptr());
+}
+
+SharedMemoryTracker::SharedMemoryTracker() {
+  trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "SharedMemoryTracker", nullptr);
+}
+
+SharedMemoryTracker::~SharedMemoryTracker() = default;
+
+bool SharedMemoryTracker::OnMemoryDump(const trace_event::MemoryDumpArgs& args,
+                                       trace_event::ProcessMemoryDump* pmd) {
+  AutoLock hold(usages_lock_);
+  for (const auto& usage : usages_) {
+    const trace_event::MemoryAllocatorDump* dump =
+        GetOrCreateSharedMemoryDumpInternal(
+            usage.first, usage.second.mapped_size, usage.second.mapped_id, pmd);
+    DCHECK(dump);
+  }
+  return true;
+}
+
+// static
+const trace_event::MemoryAllocatorDump*
+SharedMemoryTracker::GetOrCreateSharedMemoryDumpInternal(
+    void* mapped_memory,
+    size_t mapped_size,
+    const UnguessableToken& mapped_id,
+    trace_event::ProcessMemoryDump* pmd) {
+  const std::string dump_name = GetDumpNameForTracing(mapped_id);
   trace_event::MemoryAllocatorDump* local_dump =
       pmd->GetAllocatorDump(dump_name);
   if (local_dump)
     return local_dump;
 
-  size_t virtual_size = shared_memory->mapped_size();
+  size_t virtual_size = mapped_size;
   // If resident size is not available, a virtual size is used as fallback.
   size_t size = virtual_size;
 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
   base::Optional<size_t> resident_size =
       trace_event::ProcessMemoryDump::CountResidentBytesInSharedMemory(
-          *shared_memory);
+          mapped_memory, mapped_size);
   if (resident_size.has_value())
     size = resident_size.value();
 #endif
@@ -63,7 +123,7 @@
   local_dump->AddScalar("virtual_size",
                         trace_event::MemoryAllocatorDump::kUnitsBytes,
                         virtual_size);
-  auto global_dump_guid = GetGlobalDumpIdForTracing(shared_memory->mapped_id());
+  auto global_dump_guid = GetGlobalDumpIdForTracing(mapped_id);
   trace_event::MemoryAllocatorDump* global_dump =
       pmd->CreateSharedGlobalAllocatorDump(global_dump_guid);
   global_dump->AddScalar(trace_event::MemoryAllocatorDump::kNameSize,
@@ -75,38 +135,4 @@
   return local_dump;
 }
 
-void SharedMemoryTracker::IncrementMemoryUsage(
-    const SharedMemory& shared_memory) {
-  AutoLock hold(usages_lock_);
-  DCHECK(usages_.find(&shared_memory) == usages_.end());
-  usages_[&shared_memory] = shared_memory.mapped_size();
-}
-
-void SharedMemoryTracker::DecrementMemoryUsage(
-    const SharedMemory& shared_memory) {
-  AutoLock hold(usages_lock_);
-  DCHECK(usages_.find(&shared_memory) != usages_.end());
-  usages_.erase(&shared_memory);
-}
-
-bool SharedMemoryTracker::OnMemoryDump(const trace_event::MemoryDumpArgs& args,
-                                       trace_event::ProcessMemoryDump* pmd) {
-  {
-    AutoLock hold(usages_lock_);
-    for (const auto& usage : usages_) {
-      const trace_event::MemoryAllocatorDump* dump =
-          GetOrCreateSharedMemoryDump(usage.first, pmd);
-      DCHECK(dump);
-    }
-  }
-  return true;
-}
-
-SharedMemoryTracker::SharedMemoryTracker() {
-  trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      this, "SharedMemoryTracker", nullptr);
-}
-
-SharedMemoryTracker::~SharedMemoryTracker() = default;
-
 }  // namespace
diff --git a/base/memory/shared_memory_tracker.h b/base/memory/shared_memory_tracker.h
index 9b1e121..66fa160 100644
--- a/base/memory/shared_memory_tracker.h
+++ b/base/memory/shared_memory_tracker.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_mapping.h"
 #include "base/synchronization/lock.h"
 #include "base/trace_event/memory_dump_provider.h"
 
@@ -38,11 +39,15 @@
       const SharedMemory* shared_memory,
       trace_event::ProcessMemoryDump* pmd);
 
-  // Records shared memory usage on mapping.
+  // Records shared memory usage on valid mapping.
   void IncrementMemoryUsage(const SharedMemory& shared_memory);
+  // We're in the middle of a refactor https://crbug.com/795291. Eventually, the
+  // first call will go away.
+  void IncrementMemoryUsage(const SharedMemoryMapping& mapping);
 
   // Records shared memory usage on unmapping.
   void DecrementMemoryUsage(const SharedMemory& shared_memory);
+  void DecrementMemoryUsage(const SharedMemoryMapping& mapping);
 
   // Root dump name for all shared memory dumps.
   static const char kDumpRootName[];
@@ -55,9 +60,24 @@
   bool OnMemoryDump(const trace_event::MemoryDumpArgs& args,
                     trace_event::ProcessMemoryDump* pmd) override;
 
+  static const trace_event::MemoryAllocatorDump*
+  GetOrCreateSharedMemoryDumpInternal(void* mapped_memory,
+                                      size_t mapped_size,
+                                      const UnguessableToken& mapped_id,
+                                      trace_event::ProcessMemoryDump* pmd);
+
+  // Information associated with each mapped address.
+  struct UsageInfo {
+    UsageInfo(size_t size, const UnguessableToken& id)
+        : mapped_size(size), mapped_id(id) {}
+
+    size_t mapped_size;
+    UnguessableToken mapped_id;
+  };
+
   // Used to lock when |usages_| is modified or read.
   Lock usages_lock_;
-  std::map<const SharedMemory*, size_t> usages_;
+  std::map<void*, UsageInfo> usages_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedMemoryTracker);
 };
diff --git a/base/memory/unsafe_shared_memory_region.cc b/base/memory/unsafe_shared_memory_region.cc
new file mode 100644
index 0000000..60f01ba
--- /dev/null
+++ b/base/memory/unsafe_shared_memory_region.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/unsafe_shared_memory_region.h"
+
+#include <utility>
+
+#include "base/memory/shared_memory.h"
+
+namespace base {
+
+// static
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Create(size_t size) {
+  subtle::PlatformSharedMemoryRegion handle =
+      subtle::PlatformSharedMemoryRegion::CreateUnsafe(size);
+
+  return UnsafeSharedMemoryRegion(std::move(handle));
+}
+
+// static
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Deserialize(
+    subtle::PlatformSharedMemoryRegion handle) {
+  return UnsafeSharedMemoryRegion(std::move(handle));
+}
+
+// static
+subtle::PlatformSharedMemoryRegion
+UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+    UnsafeSharedMemoryRegion region) {
+  return std::move(region.handle_);
+}
+
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion() = default;
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
+    UnsafeSharedMemoryRegion&& region) = default;
+UnsafeSharedMemoryRegion& UnsafeSharedMemoryRegion::operator=(
+    UnsafeSharedMemoryRegion&& region) = default;
+UnsafeSharedMemoryRegion::~UnsafeSharedMemoryRegion() = default;
+
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Duplicate() {
+  return UnsafeSharedMemoryRegion(handle_.Duplicate());
+}
+
+WritableSharedMemoryMapping UnsafeSharedMemoryRegion::Map() {
+  return MapAt(0, handle_.GetSize());
+}
+
+WritableSharedMemoryMapping UnsafeSharedMemoryRegion::MapAt(off_t offset,
+                                                            size_t size) {
+  if (!IsValid())
+    return {};
+
+  void* memory = nullptr;
+  size_t mapped_size = 0;
+  if (!handle_.MapAt(offset, size, &memory, &mapped_size))
+    return {};
+
+  return WritableSharedMemoryMapping(memory, mapped_size, handle_.GetGUID());
+}
+
+bool UnsafeSharedMemoryRegion::IsValid() {
+  return handle_.IsValid();
+}
+
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
+    subtle::PlatformSharedMemoryRegion handle)
+    : handle_(std::move(handle)) {
+  CHECK_EQ(handle_.GetMode(),
+           subtle::PlatformSharedMemoryRegion::Mode::kUnsafe);
+}
+
+}  // namespace base
diff --git a/base/memory/unsafe_shared_memory_region.h b/base/memory/unsafe_shared_memory_region.h
new file mode 100644
index 0000000..0d792d8
--- /dev/null
+++ b/base/memory/unsafe_shared_memory_region.h
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
+
+#include "base/macros.h"
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
+
+namespace base {
+
+// Scoped move-only handle to a region of platform shared memory. The instance
+// owns the platform handle it wraps. Mappings created by this region are
+// writable. These mappings remain valid even after the region handle is moved
+// or destroyed.
+//
+// NOTE: UnsafeSharedMemoryRegion cannot be converted to a read-only region. Use
+// with caution as the region will be writable to any process with a handle to
+// the region.
+//
+// Use this if and only if the following is true:
+// - You do not need to share the region as read-only, and,
+// - You need to have several instances of the region simultaneously, possibly
+//   in different processes, that can produce writable mappings.
+
+class BASE_EXPORT UnsafeSharedMemoryRegion {
+ public:
+  using MappingType = WritableSharedMemoryMapping;
+  // Creates a new UnsafeSharedMemoryRegion instance of a given size that can be
+  // used for mapping writable shared memory into the virtual address space.
+  static UnsafeSharedMemoryRegion Create(size_t size);
+
+  // Returns an UnsafeSharedMemoryRegion built from a platform-specific handle
+  // that was taken from another UnsafeSharedMemoryRegion instance. Returns an
+  // invalid region iff the |handle| is invalid. CHECK-fails if the |handle|
+  // isn't unsafe.
+  // This should be used only by the code passing a handle across
+  // process boundaries.
+  static UnsafeSharedMemoryRegion Deserialize(
+      subtle::PlatformSharedMemoryRegion handle);
+
+  // Extracts a platform handle from the region. Ownership is transferred to the
+  // returned region object.
+  // This should be used only for sending the handle from the current
+  // process to another.
+  static subtle::PlatformSharedMemoryRegion TakeHandleForSerialization(
+      UnsafeSharedMemoryRegion region);
+
+  // Default constructor initializes an invalid instance.
+  UnsafeSharedMemoryRegion();
+
+  // Move operations are allowed.
+  UnsafeSharedMemoryRegion(UnsafeSharedMemoryRegion&&);
+  UnsafeSharedMemoryRegion& operator=(UnsafeSharedMemoryRegion&&);
+
+  // Destructor closes shared memory region if valid.
+  // All created mappings will remain valid.
+  ~UnsafeSharedMemoryRegion();
+
+  // Duplicates the underlying platform handle and creates a new
+  // UnsafeSharedMemoryRegion instance that owns the newly created handle.
+  // Returns a valid UnsafeSharedMemoryRegion on success, invalid otherwise.
+  // The current region instance remains valid in any case.
+  UnsafeSharedMemoryRegion Duplicate();
+
+  // Maps the shared memory region into the caller's address space with write
+  // access. The mapped address is guaranteed to have an alignment of
+  // at least |subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment|.
+  // Returns a valid WritableSharedMemoryMapping instance on success, invalid
+  // otherwise.
+  WritableSharedMemoryMapping Map();
+
+  // Same as above, but maps only |size| bytes of the shared memory region
+  // starting with the given |offset|. |offset| must be aligned to value of
+  // |SysInfo::VMAllocationGranularity()|. Returns an invalid mapping if
+  // requested bytes are out of the region limits.
+  WritableSharedMemoryMapping MapAt(off_t offset, size_t size);
+
+  // Whether the underlying platform handle is valid.
+  bool IsValid();
+
+  // Returns the maximum mapping size that can be created from this region.
+  size_t GetSize() {
+    DCHECK(IsValid());
+    return handle_.GetSize();
+  }
+
+ private:
+  explicit UnsafeSharedMemoryRegion(subtle::PlatformSharedMemoryRegion handle);
+
+  subtle::PlatformSharedMemoryRegion handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnsafeSharedMemoryRegion);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
diff --git a/base/memory/writable_shared_memory_region.cc b/base/memory/writable_shared_memory_region.cc
new file mode 100644
index 0000000..2048ef7
--- /dev/null
+++ b/base/memory/writable_shared_memory_region.cc
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/writable_shared_memory_region.h"
+
+#include <utility>
+
+#include "base/memory/shared_memory.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// static
+WritableSharedMemoryRegion WritableSharedMemoryRegion::Create(size_t size) {
+  subtle::PlatformSharedMemoryRegion handle =
+      subtle::PlatformSharedMemoryRegion::CreateWritable(size);
+
+  return WritableSharedMemoryRegion(std::move(handle));
+}
+
+// static
+WritableSharedMemoryRegion WritableSharedMemoryRegion::Deserialize(
+    subtle::PlatformSharedMemoryRegion handle) {
+  return WritableSharedMemoryRegion(std::move(handle));
+}
+
+// static
+subtle::PlatformSharedMemoryRegion
+WritableSharedMemoryRegion::TakeHandleForSerialization(
+    WritableSharedMemoryRegion region) {
+  return std::move(region.handle_);
+}
+
+// static
+ReadOnlySharedMemoryRegion WritableSharedMemoryRegion::ConvertToReadOnly(
+    WritableSharedMemoryRegion region) {
+  subtle::PlatformSharedMemoryRegion handle = std::move(region.handle_);
+  if (!handle.ConvertToReadOnly())
+    return {};
+
+  return ReadOnlySharedMemoryRegion::Deserialize(std::move(handle));
+}
+
+WritableSharedMemoryRegion::WritableSharedMemoryRegion() = default;
+WritableSharedMemoryRegion::WritableSharedMemoryRegion(
+    WritableSharedMemoryRegion&& region) = default;
+WritableSharedMemoryRegion& WritableSharedMemoryRegion::operator=(
+    WritableSharedMemoryRegion&& region) = default;
+WritableSharedMemoryRegion::~WritableSharedMemoryRegion() = default;
+
+WritableSharedMemoryMapping WritableSharedMemoryRegion::Map() {
+  return MapAt(0, handle_.GetSize());
+}
+
+WritableSharedMemoryMapping WritableSharedMemoryRegion::MapAt(off_t offset,
+                                                              size_t size) {
+  if (!IsValid())
+    return {};
+
+  void* memory = nullptr;
+  size_t mapped_size = 0;
+  if (!handle_.MapAt(offset, size, &memory, &mapped_size))
+    return {};
+
+  return WritableSharedMemoryMapping(memory, mapped_size, handle_.GetGUID());
+}
+
+bool WritableSharedMemoryRegion::IsValid() {
+  return handle_.IsValid();
+}
+
+WritableSharedMemoryRegion::WritableSharedMemoryRegion(
+    subtle::PlatformSharedMemoryRegion handle)
+    : handle_(std::move(handle)) {
+  CHECK_EQ(handle_.GetMode(),
+           subtle::PlatformSharedMemoryRegion::Mode::kWritable);
+}
+
+}  // namespace base
diff --git a/base/memory/writable_shared_memory_region.h b/base/memory/writable_shared_memory_region.h
new file mode 100644
index 0000000..a6766ee
--- /dev/null
+++ b/base/memory/writable_shared_memory_region.h
@@ -0,0 +1,97 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_
+
+#include "base/macros.h"
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
+
+namespace base {
+
+// Scoped move-only handle to a region of platform shared memory. The instance
+// owns the platform handle it wraps. Mappings created by this region are
+// writable. These mappings remain valid even after the region handle is moved
+// or destroyed.
+//
+// This region can be locked to read-only access by converting it to a
+// ReadOnlySharedMemoryRegion. However, unlike ReadOnlySharedMemoryRegion and
+// UnsafeSharedMemoryRegion, ownership of this region (while writable) is unique
+// and may only be transferred, not duplicated.
+class BASE_EXPORT WritableSharedMemoryRegion {
+ public:
+  using MappingType = WritableSharedMemoryMapping;
+  // Creates a new WritableSharedMemoryRegion instance of a given
+  // size that can be used for mapping writable shared memory into the virtual
+  // address space.
+  static WritableSharedMemoryRegion Create(size_t size);
+
+  // Returns a WritableSharedMemoryRegion built from a platform handle that was
+  // taken from another WritableSharedMemoryRegion instance. Returns an invalid
+  // region iff the |handle| is invalid. CHECK-fails if the |handle| isn't
+  // writable.
+  // This should be used only by the code passing handles across process
+  // boundaries.
+  static WritableSharedMemoryRegion Deserialize(
+      subtle::PlatformSharedMemoryRegion handle);
+
+  // Extracts a platform handle from the region. Ownership is transferred to the
+  // returned region object.
+  // This should be used only for sending the handle from the current
+  // process to another.
+  static subtle::PlatformSharedMemoryRegion TakeHandleForSerialization(
+      WritableSharedMemoryRegion region);
+
+  // Makes the region read-only. No new writable mappings of the region can be
+  // created after this call. Returns an invalid region on failure.
+  static ReadOnlySharedMemoryRegion ConvertToReadOnly(
+      WritableSharedMemoryRegion region);
+
+  // Default constructor initializes an invalid instance.
+  WritableSharedMemoryRegion();
+
+  // Move operations are allowed.
+  WritableSharedMemoryRegion(WritableSharedMemoryRegion&&);
+  WritableSharedMemoryRegion& operator=(WritableSharedMemoryRegion&&);
+
+  // Destructor closes shared memory region if valid.
+  // All created mappings will remain valid.
+  ~WritableSharedMemoryRegion();
+
+  // Maps the shared memory region into the caller's address space with write
+  // access. The mapped address is guaranteed to have an alignment of
+  // at least |subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment|.
+  // Returns a valid WritableSharedMemoryMapping instance on success, invalid
+  // otherwise.
+  WritableSharedMemoryMapping Map();
+
+  // Same as above, but maps only |size| bytes of the shared memory block
+  // starting with the given |offset|. |offset| must be aligned to value of
+  // |SysInfo::VMAllocationGranularity()|. Returns an invalid mapping if
+  // requested bytes are out of the region limits.
+  WritableSharedMemoryMapping MapAt(off_t offset, size_t size);
+
+  // Whether underlying platform handles are valid.
+  bool IsValid();
+
+  // Returns the maximum mapping size that can be created from this region.
+  size_t GetSize() {
+    DCHECK(IsValid());
+    return handle_.GetSize();
+  }
+
+ private:
+  explicit WritableSharedMemoryRegion(
+      subtle::PlatformSharedMemoryRegion handle);
+
+  subtle::PlatformSharedMemoryRegion handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(WritableSharedMemoryRegion);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_
diff --git a/base/test/test_shared_memory_util.cc b/base/test/test_shared_memory_util.cc
index 35d2aeeb..ebe8345 100644
--- a/base/test/test_shared_memory_util.cc
+++ b/base/test/test_shared_memory_util.cc
@@ -71,12 +71,12 @@
 
 #if defined(OS_FUCHSIA)
 // Fuchsia specific implementation.
-bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
+bool CheckReadOnlySharedMemoryFuchsiaHandle(zx_handle_t handle) {
   const uint32_t flags = ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE;
   uintptr_t addr;
   const zx_handle_t root = zx_vmar_root_self();
   const zx_status_t status =
-      zx_vmar_map(root, 0, handle.GetHandle(), 0U, kDataSize, flags, &addr);
+      zx_vmar_map(root, 0, handle, 0U, kDataSize, flags, &addr);
   if (status == ZX_OK) {
     LOG(ERROR) << "zx_vmar_map() should have failed!";
     zx_vmar_unmap(root, addr, kDataSize);
@@ -89,16 +89,13 @@
   }
   return true;
 }
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-// For OSX, the code has to deal with both POSIX and MACH handles.
-bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
-  if (handle.type_ == SharedMemoryHandle::POSIX)
-    return CheckReadOnlySharedMemoryFdPosix(handle.file_descriptor_.fd);
 
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+bool CheckReadOnlySharedMemoryMachPort(mach_port_t memory_object) {
   mach_vm_address_t memory;
   const kern_return_t kr = mach_vm_map(
-      mach_task_self(), &memory, kDataSize, 0, VM_FLAGS_ANYWHERE,
-      handle.memory_object_, 0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
+      mach_task_self(), &memory, kDataSize, 0, VM_FLAGS_ANYWHERE, memory_object,
+      0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
       VM_PROT_READ | VM_PROT_WRITE | VM_PROT_IS_MASK, VM_INHERIT_NONE);
   if (kr == KERN_SUCCESS) {
     LOG(ERROR) << "mach_vm_map() should have failed!";
@@ -107,10 +104,11 @@
   }
   return true;
 }
+
 #elif defined(OS_WIN)
-bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
-  void* memory = MapViewOfFile(handle.GetHandle(),
-                               FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kDataSize);
+bool CheckReadOnlySharedMemoryWindowsHandle(HANDLE handle) {
+  void* memory =
+      MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kDataSize);
   if (memory != nullptr) {
     LOG(ERROR) << "MapViewOfFile() should have failed!";
     UnmapViewOfFile(memory);
@@ -118,12 +116,47 @@
   }
   return true;
 }
-#else
-bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
-  return CheckReadOnlySharedMemoryFdPosix(handle.GetHandle());
-}
 #endif
 
+bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // For OSX, the code has to deal with both POSIX and MACH handles.
+  if (handle.type_ == SharedMemoryHandle::POSIX)
+    return CheckReadOnlySharedMemoryFdPosix(handle.file_descriptor_.fd);
+  else
+    return CheckReadOnlySharedMemoryMachPort(handle.memory_object_);
+#elif defined(OS_FUCHSIA)
+  return CheckReadOnlySharedMemoryFuchsiaHandle(handle.GetHandle());
+#elif defined(OS_WIN)
+  return CheckReadOnlySharedMemoryWindowsHandle(handle.GetHandle());
+#else
+  return CheckReadOnlySharedMemoryFdPosix(handle.GetHandle());
+#endif
+}
+
+bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+    subtle::PlatformSharedMemoryRegion region) {
+  if (region.GetMode() != subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
+    LOG(ERROR) << "Expected region mode is "
+               << static_cast<int>(
+                      subtle::PlatformSharedMemoryRegion::Mode::kReadOnly)
+               << " but actual is " << static_cast<int>(region.GetMode());
+    return false;
+  }
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  return CheckReadOnlySharedMemoryMachPort(region.GetPlatformHandle());
+#elif defined(OS_FUCHSIA)
+  return CheckReadOnlySharedMemoryFuchsiaHandle(region.GetPlatformHandle());
+#elif defined(OS_WIN)
+  return CheckReadOnlySharedMemoryWindowsHandle(region.GetPlatformHandle());
+#elif defined(OS_ANDROID)
+  return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle());
+#else
+  return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle().fd);
+#endif
+}
+
 #endif  // !OS_NACL
 
 }  // namespace base
diff --git a/base/test/test_shared_memory_util.h b/base/test/test_shared_memory_util.h
index ee657da..7acb555 100644
--- a/base/test/test_shared_memory_util.h
+++ b/base/test/test_shared_memory_util.h
@@ -5,6 +5,7 @@
 #ifndef BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
 #define BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
 
+#include "base/memory/platform_shared_memory_region.h"
 #include "base/memory/shared_memory_handle.h"
 
 namespace base {
@@ -15,6 +16,9 @@
 // otherwise.
 bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle);
 
+bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+    subtle::PlatformSharedMemoryRegion region);
+
 }  // namespace base
 
 #endif  // BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 8237a23..a88d70f 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -271,6 +271,9 @@
   static bool GetThreadWasQuitProperly();
 
   // Bind this Thread to an existing MessageLoop instead of starting a new one.
+  // TODO(gab): Remove this after ios/ has undergone the same surgery as
+  // BrowserThreadImpl (ref.
+  // https://chromium-review.googlesource.com/c/chromium/src/+/969104).
   void SetMessageLoop(MessageLoop* message_loop);
 
   bool using_external_message_loop() const {
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index fa97031..0cc506c 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -38,6 +38,7 @@
 class BrowserGpuChannelHostFactory;
 class BrowserGpuMemoryBufferManager;
 class BrowserMainLoop;
+class BrowserProcessSubThread;
 class BrowserShutdownProfileDumper;
 class BrowserSurfaceViewManager;
 class BrowserTestBase;
@@ -211,6 +212,7 @@
   // in unit tests to avoid the friend requirement.
   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking);
   friend class android_webview::ScopedAllowInitGLBindings;
+  friend class content::BrowserProcessSubThread;
   friend class cronet::CronetPrefsManager;
   friend class cronet::CronetURLRequestContext;
   friend class resource_coordinator::TabManagerDelegate;  // crbug.com/778703
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
index 8f0e7ba..002bb00 100644
--- a/base/trace_event/common/trace_event_common.h
+++ b/base/trace_event/common/trace_event_common.h
@@ -687,6 +687,11 @@
       TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
       TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
       arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
+                                                   timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
 
 // NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
 // be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index c36e670..8313caa 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "base/memory/shared_memory.h"
 #include "base/memory/shared_memory_tracker.h"
 #include "base/process/process_metrics.h"
 #include "base/strings/stringprintf.h"
@@ -164,13 +163,14 @@
 
 // static
 base::Optional<size_t> ProcessMemoryDump::CountResidentBytesInSharedMemory(
-    const SharedMemory& shared_memory) {
+    void* start_address,
+    size_t mapped_size) {
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   // On macOS, use mach_vm_region instead of mincore for performance
   // (crbug.com/742042).
   mach_vm_size_t dummy_size = 0;
   mach_vm_address_t address =
-      reinterpret_cast<mach_vm_address_t>(shared_memory.memory());
+      reinterpret_cast<mach_vm_address_t>(start_address);
   vm_region_top_info_data_t info;
   MachVMRegionResult result =
       GetTopInfo(mach_task_self(), &dummy_size, &address, &info);
@@ -212,10 +212,9 @@
   // Sanity check in case the mapped size is less than the total size of the
   // region.
   size_t pages_to_fault =
-      std::min(resident_pages,
-               (shared_memory.mapped_size() + PAGE_SIZE - 1) / PAGE_SIZE);
+      std::min(resident_pages, (mapped_size + PAGE_SIZE - 1) / PAGE_SIZE);
 
-  volatile char* base_address = static_cast<char*>(shared_memory.memory());
+  volatile char* base_address = static_cast<char*>(start_address);
   for (size_t i = 0; i < pages_to_fault; ++i) {
     // Reading from a volatile is a visible side-effect for the purposes of
     // optimization. This guarantees that the optimizer will not kill this line.
@@ -224,8 +223,7 @@
 
   return resident_pages * PAGE_SIZE;
 #else
-  return CountResidentBytes(shared_memory.memory(),
-                            shared_memory.mapped_size());
+  return CountResidentBytes(start_address, mapped_size);
 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 }
 
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index ec83c3c..345531d7 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -74,10 +74,11 @@
   // process. The |start_address| must be page-aligned.
   static size_t CountResidentBytes(void* start_address, size_t mapped_size);
 
-  // Returns the total bytes resident for the given |shared_memory|'s mapped
-  // region.
+  // The same as above, but the given mapped range should belong to the
+  // shared_memory's mapped region.
   static base::Optional<size_t> CountResidentBytesInSharedMemory(
-      const SharedMemory& shared_memory);
+      void* start_address,
+      size_t mapped_size);
 #endif
 
   ProcessMemoryDump(scoped_refptr<HeapProfilerSerializationState>
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
index 934f986..8aed15a2 100644
--- a/base/trace_event/process_memory_dump_unittest.cc
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -547,7 +547,8 @@
   shared_memory1.CreateAndMapAnonymous(size1);
   memset(shared_memory1.memory(), 0, size1);
   base::Optional<size_t> res1 =
-      ProcessMemoryDump::CountResidentBytesInSharedMemory(shared_memory1);
+      ProcessMemoryDump::CountResidentBytesInSharedMemory(
+          shared_memory1.memory(), shared_memory1.mapped_size());
   ASSERT_TRUE(res1.has_value());
   ASSERT_EQ(res1.value(), size1);
   shared_memory1.Unmap();
@@ -559,7 +560,8 @@
   shared_memory2.CreateAndMapAnonymous(kVeryLargeMemorySize);
   memset(shared_memory2.memory(), 0, kVeryLargeMemorySize);
   base::Optional<size_t> res2 =
-      ProcessMemoryDump::CountResidentBytesInSharedMemory(shared_memory2);
+      ProcessMemoryDump::CountResidentBytesInSharedMemory(
+          shared_memory2.memory(), shared_memory2.mapped_size());
   ASSERT_TRUE(res2.has_value());
   ASSERT_EQ(res2.value(), kVeryLargeMemorySize);
   shared_memory2.Unmap();
@@ -571,7 +573,8 @@
   shared_memory3.CreateAndMapAnonymous(kVeryLargeMemorySize);
   memset(shared_memory3.memory(), 0, kTouchedMemorySize);
   base::Optional<size_t> res3 =
-      ProcessMemoryDump::CountResidentBytesInSharedMemory(shared_memory3);
+      ProcessMemoryDump::CountResidentBytesInSharedMemory(
+          shared_memory3.memory(), shared_memory3.mapped_size());
   ASSERT_TRUE(res3.has_value());
   ASSERT_EQ(res3.value(), kTouchedMemorySize);
   shared_memory3.Unmap();
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index ebc99b5..23b7971 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1345,13 +1345,10 @@
 
         # TODO(hans): https://crbug.com/766891
         "-Wno-null-pointer-arithmetic",
+
+        # Ignore warnings about MSVC optimization pragmas.
+        "-Wno-ignored-pragma-optimize",
       ]
-      if (llvm_force_head_revision) {
-        cflags += [
-          # TODO(crbug.com/823655): Enable by default in next clang roll.
-          "-Wno-ignored-pragma-optimize",
-        ]
-      }
     } else if (use_xcode_clang) {
       cflags += [
         # TODO(thakis): https://crbug.com/604888
diff --git a/build/config/linux/atk/BUILD.gn b/build/config/linux/atk/BUILD.gn
index 16a3f8c..89eedff 100644
--- a/build/config/linux/atk/BUILD.gn
+++ b/build/config/linux/atk/BUILD.gn
@@ -39,12 +39,14 @@
   configs = [ ":atk_base" ]
 
   cflags = [
-    # glib uses the pre-c++11 typedef-as-static_assert hack.
-    "-Wno-unused-local-typedef",
-
     # G_DEFINE_TYPE automatically generates a *get_instance_private
     # inline function after glib 2.37. That's unused. Prevent to
     # complain about it.
     "-Wno-unused-function",
   ]
+
+  if (is_clang) {
+    # glib uses the pre-c++11 typedef-as-static_assert hack.
+    cflags += [ "-Wno-unused-local-typedef" ]
+  }
 }
diff --git a/build/util/lastchange.py b/build/util/lastchange.py
index 9ade784..a64bf92 100755
--- a/build/util/lastchange.py
+++ b/build/util/lastchange.py
@@ -8,6 +8,7 @@
 """
 
 import re
+import logging
 import optparse
 import os
 import subprocess
@@ -42,7 +43,8 @@
                             cwd=directory,
                             shell=(sys.platform=='win32'))
     return proc
-  except OSError:
+  except OSError as e:
+    logging.error('Command %r failed: %s' % (' '.join(command), e))
     return None
 
 
@@ -174,6 +176,8 @@
                     default='^Change-Id:')
   opts, args = parser.parse_args(argv[1:])
 
+  logging.basicConfig(level=logging.WARNING)
+
   out_file = opts.output
   header = opts.header
   filter=opts.filter
diff --git a/cc/paint/paint_typeface_transfer_cache_entry.cc b/cc/paint/paint_typeface_transfer_cache_entry.cc
index 4cb623aaf6..34def03d 100644
--- a/cc/paint/paint_typeface_transfer_cache_entry.cc
+++ b/cc/paint/paint_typeface_transfer_cache_entry.cc
@@ -198,7 +198,7 @@
 
   // Set the size to however much data we read.
   size_ = initial_size - data_.size();
-  data_ = base::span<uint8_t>(nullptr);
+  data_ = base::span<uint8_t>();
   return valid_;
 }
 
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index bd01caf..e5481a0c 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -51,7 +51,7 @@
 // Generates process-unique IDs to use for tracing video resources.
 base::AtomicSequenceNumber g_next_video_resource_updater_id;
 
-VideoFrameExternalResources::ResourceType ExternalResourceTypeForHardwarePlanes(
+VideoFrameResourceType ExternalResourceTypeForHardwarePlanes(
     media::VideoPixelFormat format,
     GLuint target,
     int num_textures,
@@ -66,21 +66,21 @@
       switch (target) {
         case GL_TEXTURE_EXTERNAL_OES:
           if (use_stream_video_draw_quad)
-            return VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
+            return VideoFrameResourceType::STREAM_TEXTURE;
           FALLTHROUGH;
         case GL_TEXTURE_2D:
           return (format == media::PIXEL_FORMAT_XRGB)
-                     ? VideoFrameExternalResources::RGB_RESOURCE
-                     : VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
+                     ? VideoFrameResourceType::RGB
+                     : VideoFrameResourceType::RGBA_PREMULTIPLIED;
         case GL_TEXTURE_RECTANGLE_ARB:
-          return VideoFrameExternalResources::RGB_RESOURCE;
+          return VideoFrameResourceType::RGB;
         default:
           NOTREACHED();
           break;
       }
       break;
     case media::PIXEL_FORMAT_I420:
-      return VideoFrameExternalResources::YUV_RESOURCE;
+      return VideoFrameResourceType::YUV;
     case media::PIXEL_FORMAT_NV12:
       DCHECK(target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_2D ||
              target == GL_TEXTURE_RECTANGLE_ARB)
@@ -88,10 +88,10 @@
           << target;
       // Single plane textures can be sampled as RGB.
       if (num_textures > 1)
-        return VideoFrameExternalResources::YUV_RESOURCE;
+        return VideoFrameResourceType::YUV;
 
       *buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
-      return VideoFrameExternalResources::RGB_RESOURCE;
+      return VideoFrameResourceType::RGB;
     case media::PIXEL_FORMAT_YV12:
     case media::PIXEL_FORMAT_I422:
     case media::PIXEL_FORMAT_I444:
@@ -114,7 +114,7 @@
     case media::PIXEL_FORMAT_UNKNOWN:
       break;
   }
-  return VideoFrameExternalResources::NONE;
+  return VideoFrameResourceType::NONE;
 }
 
 class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient {
@@ -368,7 +368,7 @@
       CreateExternalResourcesFromVideoFrame(video_frame);
   frame_resource_type_ = external_resources.type;
 
-  if (external_resources.type == VideoFrameExternalResources::YUV_RESOURCE) {
+  if (external_resources.type == VideoFrameResourceType::YUV) {
     frame_resource_offset_ = external_resources.offset;
     frame_resource_multiplier_ = external_resources.multiplier;
     frame_bits_per_channel_ = external_resources.bits_per_channel;
@@ -426,7 +426,7 @@
       static_cast<float>(visible_rect.height()) / coded_size.height();
 
   switch (frame_resource_type_) {
-    case VideoFrameExternalResources::YUV_RESOURCE: {
+    case VideoFrameResourceType::YUV: {
       const gfx::Size ya_tex_size = coded_size;
 
       int u_width = media::VideoFrame::Columns(
@@ -483,15 +483,14 @@
       }
       break;
     }
-    case VideoFrameExternalResources::RGBA_RESOURCE:
-    case VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE:
-    case VideoFrameExternalResources::RGB_RESOURCE: {
+    case VideoFrameResourceType::RGBA:
+    case VideoFrameResourceType::RGBA_PREMULTIPLIED:
+    case VideoFrameResourceType::RGB: {
       DCHECK_EQ(frame_resources_.size(), 1u);
       if (frame_resources_.size() < 1u)
         break;
       bool premultiplied_alpha =
-          frame_resource_type_ ==
-          VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
+          frame_resource_type_ == VideoFrameResourceType::RGBA_PREMULTIPLIED;
       gfx::PointF uv_top_left(0.f, 0.f);
       gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
       float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
@@ -510,7 +509,7 @@
       }
       break;
     }
-    case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
+    case VideoFrameResourceType::STREAM_TEXTURE: {
       DCHECK_EQ(frame_resources_.size(), 1u);
       if (frame_resources_.size() < 1u)
         break;
@@ -526,7 +525,7 @@
       }
       break;
     }
-    case VideoFrameExternalResources::NONE:
+    case VideoFrameResourceType::NONE:
       NOTIMPLEMENTED();
       break;
   }
@@ -682,15 +681,14 @@
   external_resources.type = ExternalResourceTypeForHardwarePlanes(
       video_frame->format(), target, video_frame->NumTextures(), &buffer_format,
       use_stream_video_draw_quad_);
-  if (external_resources.type == VideoFrameExternalResources::NONE) {
+  if (external_resources.type == VideoFrameResourceType::NONE) {
     DLOG(ERROR) << "Unsupported Texture format"
                 << media::VideoPixelFormatToString(video_frame->format());
     return external_resources;
   }
-  if (external_resources.type == VideoFrameExternalResources::RGB_RESOURCE ||
-      external_resources.type == VideoFrameExternalResources::RGBA_RESOURCE ||
-      external_resources.type ==
-          VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE) {
+  if (external_resources.type == VideoFrameResourceType::RGB ||
+      external_resources.type == VideoFrameResourceType::RGBA ||
+      external_resources.type == VideoFrameResourceType::RGBA_PREMULTIPLIED) {
     resource_color_space = resource_color_space.GetAsFullRangeRGB();
   }
 
@@ -870,8 +868,7 @@
 
     if (software_compositor()) {
       SoftwarePlaneResource* software_resource = plane_resource->AsSoftware();
-      external_resources.type =
-          VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
+      external_resources.type = VideoFrameResourceType::RGBA_PREMULTIPLIED;
       external_resources.resources.push_back(
           viz::TransferableResource::MakeSoftware(
               software_resource->shared_bitmap_id(), 0 /* sequence_number */,
@@ -879,7 +876,7 @@
               plane_resource->resource_format()));
     } else {
       HardwarePlaneResource* hardware_resource = plane_resource->AsHardware();
-      external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE;
+      external_resources.type = VideoFrameResourceType::RGBA;
       gpu::SyncToken sync_token;
       GenerateCompositorSyncToken(context_provider_->ContextGL(), &sync_token);
       external_resources.resources.push_back(
@@ -1038,7 +1035,7 @@
         plane_resource->plane_resource_id()));
   }
 
-  external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
+  external_resources.type = VideoFrameResourceType::YUV;
   return external_resources;
 }
 
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index da30385..6d152ef 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -44,19 +44,20 @@
 class LayerTreeFrameSink;
 class LayerTreeResourceProvider;
 
+// Specifies what type of data is contained in the mailboxes, as well as how
+// many mailboxes will be present.
+enum class VideoFrameResourceType {
+  NONE,
+  YUV,
+  RGB,
+  RGBA_PREMULTIPLIED,
+  RGBA,
+  STREAM_TEXTURE,
+};
+
 class CC_EXPORT VideoFrameExternalResources {
  public:
-  // Specifies what type of data is contained in the mailboxes, as well as how
-  // many mailboxes will be present.
-  enum ResourceType {
-    NONE,
-    YUV_RESOURCE,
-    RGB_RESOURCE,
-    RGBA_PREMULTIPLIED_RESOURCE,
-    RGBA_RESOURCE,
-    STREAM_TEXTURE_RESOURCE,
-  };
-  ResourceType type = NONE;
+  VideoFrameResourceType type = VideoFrameResourceType::NONE;
   std::vector<viz::TransferableResource> resources;
   std::vector<viz::ReleaseCallback> release_callbacks;
 
@@ -191,7 +192,7 @@
   // Temporary pixel buffer when converting between formats.
   std::vector<uint8_t> upload_pixels_;
 
-  VideoFrameExternalResources::ResourceType frame_resource_type_;
+  VideoFrameResourceType frame_resource_type_;
 
   float frame_resource_offset_;
   float frame_resource_multiplier_;
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 6c1ec994..ab5dccf 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -22,8 +22,6 @@
 namespace cc {
 namespace {
 
-constexpr bool kUseGpuMemoryBufferResources = false;
-
 class WebGraphicsContext3DUploadCounter : public viz::TestWebGraphicsContext3D {
  public:
   void texSubImage2D(GLenum target,
@@ -71,23 +69,6 @@
   int created_texture_count_;
 };
 
-class SharedBitmapManagerAllocationCounter
-    : public viz::TestSharedBitmapManager {
- public:
-  std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
-      const gfx::Size& size,
-      viz::ResourceFormat resource_format) override {
-    ++allocation_count_;
-    return TestSharedBitmapManager::AllocateSharedBitmap(size, resource_format);
-  }
-
-  int AllocationCount() { return allocation_count_; }
-  void ResetAllocationCount() { allocation_count_ = 0; }
-
- private:
-  int allocation_count_;
-};
-
 class VideoResourceUpdaterTest : public testing::Test {
  protected:
   VideoResourceUpdaterTest() {
@@ -101,6 +82,7 @@
     context_provider_->BindToCurrentThread();
   }
 
+  // testing::Test implementation.
   void SetUp() override {
     testing::Test::SetUp();
     layer_tree_frame_sink_software_ = FakeLayerTreeFrameSink::CreateSoftware();
@@ -112,6 +94,21 @@
             nullptr, nullptr, nullptr, high_bit_for_testing_);
   }
 
+  std::unique_ptr<VideoResourceUpdater> CreateUpdaterForHardware(
+      bool use_stream_video_draw_quad = false) {
+    return std::make_unique<VideoResourceUpdater>(
+        context_provider_.get(), nullptr, resource_provider3d_.get(),
+        use_stream_video_draw_quad, /*use_gpu_memory_buffer_resources=*/false);
+  }
+
+  std::unique_ptr<VideoResourceUpdater> CreateUpdaterForSoftware() {
+    return std::make_unique<VideoResourceUpdater>(
+        nullptr, layer_tree_frame_sink_software_.get(),
+        resource_provider_software_.get(),
+        /*use_stream_video_draw_quad=*/false,
+        /*use_gpu_memory_buffer_resources=*/false);
+  }
+
   scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
     const int kDimension = 10;
     gfx::Size size(kDimension, kDimension);
@@ -259,27 +256,21 @@
                    7);
 
 TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
 }
 
 TEST_F(VideoResourceUpdaterTest, HighBitFrameNoF16) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
 }
 
 class VideoResourceUpdaterTestWithF16 : public VideoResourceUpdaterTest {
@@ -290,23 +281,20 @@
 };
 
 TEST_F(VideoResourceUpdaterTestWithF16, HighBitFrame) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_NEAR(resources.multiplier, 2.0, 0.1);
   EXPECT_NEAR(resources.offset, 0.5, 0.1);
 
   // Create the resource again, to test the path where the
   // resources are cached.
   VideoFrameExternalResources resources2 =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources2.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources2.type);
   EXPECT_NEAR(resources2.multiplier, 2.0, 0.1);
   EXPECT_NEAR(resources2.offset, 0.5, 0.1);
 }
@@ -320,15 +308,12 @@
 };
 
 TEST_F(VideoResourceUpdaterTestWithR16, HighBitFrame) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
 
   // Max 10-bit values as read by a sampler.
   double max_10bit_value = ((1 << 10) - 1) / 65535.0;
@@ -338,65 +323,49 @@
   // Create the resource again, to test the path where the
   // resources are cached.
   VideoFrameExternalResources resources2 =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources2.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources2.type);
   EXPECT_NEAR(resources2.multiplier * max_10bit_value, 1.0, 0.0001);
   EXPECT_NEAR(resources2.offset, 0.0, 0.1);
 }
 
 TEST_F(VideoResourceUpdaterTest, HighBitFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, layer_tree_frame_sink_software_.get(),
-                               resource_provider_software_.get(),
-                               use_stream_video_draw_quad,
-                               kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
 }
 
 TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrame) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
 }
 
 TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, layer_tree_frame_sink_software_.get(),
-                               resource_provider_software_.get(),
-                               use_stream_video_draw_quad,
-                               kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
   scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResource) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
   // Allocate the resources for a YUV video frame.
   context3d_->ResetUploadCount();
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
   // Expect exactly three texture uploads, one for each plane.
@@ -409,8 +378,8 @@
 
   // Allocate resources for the same frame.
   context3d_->ResetUploadCount();
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
   // The data should be reused so expect no texture uploads.
@@ -418,18 +387,15 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
   // Allocate the resources for a YUV video frame.
   context3d_->ResetUploadCount();
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
   // Expect exactly three texture uploads, one for each plane.
@@ -437,8 +403,8 @@
 
   // Allocate resources for the same frame.
   context3d_->ResetUploadCount();
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
   // The data should be reused so expect no texture uploads.
@@ -446,102 +412,85 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, layer_tree_frame_sink_software_.get(),
-                               resource_provider_software_.get(),
-                               use_stream_video_draw_quad,
-                               kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, layer_tree_frame_sink_software_.get(),
-                               resource_provider_software_.get(),
-                               use_stream_video_draw_quad,
-                               kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
   // Allocate the resources for a software video frame.
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
   // Expect exactly one allocated shared bitmap.
   EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
+  auto shared_bitmaps = layer_tree_frame_sink_software_->shared_bitmaps();
 
   // Simulate the ResourceProvider releasing the resource back to the video
   // updater.
-  std::move(resources.release_callbacks.back()).Run(gpu::SyncToken(), false);
+  std::move(resources.release_callbacks[0]).Run(gpu::SyncToken(), false);
 
   // Allocate resources for the same frame.
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
-  // The data should be reused so expect no new allocations.
-  EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
+
+  // Ensure that the same shared bitmap was reused.
+  EXPECT_EQ(layer_tree_frame_sink_software_->shared_bitmaps(), shared_bitmaps);
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDeleteSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, layer_tree_frame_sink_software_.get(),
-                               resource_provider_software_.get(),
-                               use_stream_video_draw_quad,
-                               kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForSoftware();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
   // Allocate the resources for a software video frame.
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
   // Expect exactly one allocated shared bitmap.
   EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
+  auto shared_bitmaps = layer_tree_frame_sink_software_->shared_bitmaps();
 
   // Allocate resources for the same frame.
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
-  // The data should be reused so expect no new allocations.
-  EXPECT_EQ(1u, layer_tree_frame_sink_software_->shared_bitmaps().size());
+
+  // Ensure that the same shared bitmap was reused.
+  EXPECT_EQ(layer_tree_frame_sink_software_->shared_bitmaps(), shared_bitmaps);
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestRGBAHardwareVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
 
   video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_I420, 3,
                                                 GL_TEXTURE_RECTANGLE_ARB);
 
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
   EXPECT_FALSE(resources.resources[0].read_lock_fences_enabled);
@@ -553,25 +502,23 @@
   video_frame->metadata()->SetBoolean(
       media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, true);
 
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
   EXPECT_TRUE(resources.resources[0].read_lock_fences_enabled);
   EXPECT_TRUE(resources.resources[1].read_lock_fences_enabled);
   EXPECT_TRUE(resources.resources[2].read_lock_fences_enabled);
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_StreamTexture) {
-  bool use_stream_video_draw_quad = true;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  // Note that |use_stream_video_draw_quad| is true for this test.
+  std::unique_ptr<VideoResourceUpdater> updater =
+      CreateUpdaterForHardware(true);
   context3d_->ResetTextureCreationCount();
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestStreamTextureHardwareVideoFrame(false);
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::STREAM_TEXTURE, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
             resources.resources[0].mailbox_holder.texture_target);
@@ -582,9 +529,8 @@
   // GL_TEXTURE_2D texture.
   context3d_->ResetTextureCreationCount();
   video_frame = CreateTestStreamTextureHardwareVideoFrame(true);
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_2D,
             resources.resources[0].mailbox_holder.texture_target);
@@ -593,18 +539,14 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   context3d_->ResetTextureCreationCount();
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestStreamTextureHardwareVideoFrame(false);
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE,
-            resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
             resources.resources[0].mailbox_holder.texture_target);
@@ -615,9 +557,7 @@
 // Passthrough the sync token returned by the compositor if we don't have an
 // existing release sync token.
 TEST_F(VideoResourceUpdaterTest, PassReleaseSyncToken) {
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      false /* use_stream_video_draw_quad */, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   const gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
                                   gpu::CommandBufferId::FromUnsafeValue(0x123),
@@ -628,7 +568,7 @@
         CreateTestRGBAHardwareVideoFrame();
 
     VideoFrameExternalResources resources =
-        updater.CreateExternalResourcesFromVideoFrame(video_frame);
+        updater->CreateExternalResourcesFromVideoFrame(video_frame);
 
     ASSERT_EQ(resources.release_callbacks.size(), 1u);
     std::move(resources.release_callbacks[0]).Run(sync_token, false);
@@ -639,9 +579,7 @@
 
 // Generate new sync token because video frame has an existing sync token.
 TEST_F(VideoResourceUpdaterTest, GenerateReleaseSyncToken) {
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      false /* use_stream_video_draw_quad */, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   const gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO,
                                    gpu::CommandBufferId::FromUnsafeValue(0x123),
@@ -656,12 +594,12 @@
         CreateTestRGBAHardwareVideoFrame();
 
     VideoFrameExternalResources resources1 =
-        updater.CreateExternalResourcesFromVideoFrame(video_frame);
+        updater->CreateExternalResourcesFromVideoFrame(video_frame);
     ASSERT_EQ(resources1.release_callbacks.size(), 1u);
     std::move(resources1.release_callbacks[0]).Run(sync_token1, false);
 
     VideoFrameExternalResources resources2 =
-        updater.CreateExternalResourcesFromVideoFrame(video_frame);
+        updater->CreateExternalResourcesFromVideoFrame(video_frame);
     ASSERT_EQ(resources2.release_callbacks.size(), 1u);
     std::move(resources2.release_callbacks[0]).Run(sync_token2, false);
   }
@@ -674,15 +612,13 @@
 // Pass mailbox sync token as is if no GL operations are performed before frame
 // resources are handed off to the compositor.
 TEST_F(VideoResourceUpdaterTest, PassMailboxSyncToken) {
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      false /* use_stream_video_draw_quad */, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestRGBAHardwareVideoFrame();
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
 
   ASSERT_EQ(resources.resources.size(), 1u);
   EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
@@ -692,15 +628,13 @@
 
 // Generate new sync token for compositor when copying the texture.
 TEST_F(VideoResourceUpdaterTest, GenerateSyncTokenOnTextureCopy) {
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      false /* use_stream_video_draw_quad */, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestStreamTextureHardwareVideoFrame(true /* needs_copy */);
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
 
   ASSERT_EQ(resources.resources.size(), 1u);
   EXPECT_TRUE(resources.resources[0].mailbox_holder.sync_token.HasData());
@@ -712,17 +646,14 @@
 // by GL as RGB. To use them as HW overlays we need to know the format
 // of the underlying buffer, that is YUV_420_BIPLANAR.
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SingleNV12) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   context3d_->ResetTextureCreationCount();
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHardwareVideoFrame(
       media::PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES);
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGB_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGB, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
             resources.resources[0].mailbox_holder.texture_target);
@@ -731,8 +662,8 @@
 
   video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 1,
                                                 GL_TEXTURE_RECTANGLE_ARB);
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGB_RESOURCE, resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::RGB, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_RECTANGLE_ARB,
             resources.resources[0].mailbox_holder.texture_target);
@@ -743,18 +674,15 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_DualNV12) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(
-      context_provider_.get(), nullptr, resource_provider3d_.get(),
-      use_stream_video_draw_quad, kUseGpuMemoryBufferResources);
+  std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   context3d_->ResetTextureCreationCount();
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 2,
                                       GL_TEXTURE_EXTERNAL_OES);
 
   VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(2u, resources.resources.size());
   EXPECT_EQ(2u, resources.release_callbacks.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
@@ -764,8 +692,8 @@
 
   video_frame = CreateTestYuvHardwareVideoFrame(media::PIXEL_FORMAT_NV12, 2,
                                                 GL_TEXTURE_RECTANGLE_ARB);
-  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(2u, resources.resources.size());
   EXPECT_EQ((GLenum)GL_TEXTURE_RECTANGLE_ARB,
             resources.resources[0].mailbox_holder.texture_target);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
index bde31687..635e1b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/Origin.java
@@ -27,7 +27,7 @@
      * Constructs a canonical Origin from an Uri.
      */
     public Origin(Uri uri) {
-        if (uri.getScheme() == null || uri.getAuthority() == null) {
+        if (uri == null || uri.getScheme() == null || uri.getAuthority() == null) {
             mOrigin = Uri.EMPTY;
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 7d38d59c..f921795 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -38,6 +38,9 @@
     /** The ContentViewCore that this panel will display. */
     private ContentViewCore mContentViewCore;
 
+    /** The WebContents that this panel will display. */
+    private WebContents mWebContents;
+
     /** The pointer to the native version of this class. */
     private long mNativeOverlayPanelContentPtr;
 
@@ -152,9 +155,7 @@
 
             @Override
             public void loadingStateChanged(boolean toDifferentDocument) {
-                boolean isLoading = mContentViewCore != null
-                        && mContentViewCore.getWebContents() != null
-                        && mContentViewCore.getWebContents().isLoading();
+                boolean isLoading = mWebContents != null && mWebContents.isLoading();
                 if (isLoading) {
                     mProgressObserver.onProgressBarStarted();
                 } else {
@@ -222,8 +223,7 @@
             mDidStartLoadingUrl = true;
             mIsProcessingPendingNavigation = true;
             if (!mContentDelegate.handleInterceptLoadUrl(mContentViewCore, url)) {
-                mContentViewCore.getWebContents().getNavigationController().loadUrl(
-                        new LoadUrlParams(url));
+                mWebContents.getNavigationController().loadUrl(new LoadUrlParams(url));
             }
         }
     }
@@ -269,9 +269,9 @@
         }
 
         // Creates an initially hidden WebContents which gets shown when the panel is opened.
-        WebContents panelWebContents = WebContentsFactory.createWebContents(false, true);
+        mWebContents = WebContentsFactory.createWebContents(false, true);
 
-        ContentView cv = ContentView.createContentView(mActivity, panelWebContents);
+        ContentView cv = ContentView.createContentView(mActivity, mWebContents);
         if (mContentViewWidth != 0 || mContentViewHeight != 0) {
             int width = mContentViewWidth == 0 ? ContentView.DEFAULT_MEASURE_SPEC
                     : MeasureSpec.makeMeasureSpec(mContentViewWidth, MeasureSpec.EXACTLY);
@@ -309,13 +309,13 @@
                     }
                 }.init(cv);
         mContentViewCore = ContentViewCore.create(mActivity, ChromeVersionInfo.getProductVersion(),
-                panelWebContents, delegate, cv, mActivity.getWindowAndroid());
+                mWebContents, delegate, cv, mActivity.getWindowAndroid());
 
         // Transfers the ownership of the WebContents to the native OverlayPanelContent.
-        nativeSetWebContents(mNativeOverlayPanelContentPtr, panelWebContents, mWebContentsDelegate);
+        nativeSetWebContents(mNativeOverlayPanelContentPtr, mWebContents, mWebContentsDelegate);
 
         mWebContentsObserver =
-                new WebContentsObserver(panelWebContents) {
+                new WebContentsObserver(mWebContents) {
                     @Override
                     public void didStartLoading(String url) {
                         mContentDelegate.onContentLoadStarted(url);
@@ -351,12 +351,12 @@
 
         mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
         nativeSetInterceptNavigationDelegate(
-                mNativeOverlayPanelContentPtr, mInterceptNavigationDelegate, panelWebContents);
+                mNativeOverlayPanelContentPtr, mInterceptNavigationDelegate, mWebContents);
 
         mContentDelegate.onContentViewCreated();
         int viewHeight = mContentViewHeight - (mSubtractBarHeight ? mBarHeightPx : 0);
         onPhysicalBackingSizeChanged(mContentViewWidth, viewHeight);
-        panelWebContents.setSize(mContentViewWidth, viewHeight);
+        mWebContents.setSize(mContentViewWidth, viewHeight);
     }
 
     /**
@@ -368,6 +368,7 @@
             nativeDestroyWebContents(mNativeOverlayPanelContentPtr);
             mContentViewCore.destroy();
             mContentViewCore = null;
+            mWebContents = null;
             if (mWebContentsObserver != null) {
                 mWebContentsObserver.destroy();
                 mWebContentsObserver = null;
@@ -433,25 +434,21 @@
 
         if (isVisible) {
             // If the last call to loadUrl was specified to be delayed, load it now.
-            if (!TextUtils.isEmpty(mPendingUrl)) {
-                loadUrl(mPendingUrl, true);
-            }
+            if (!TextUtils.isEmpty(mPendingUrl)) loadUrl(mPendingUrl, true);
 
             // The CVC is created with the search request, but if none was made we'll need
             // one in order to display an empty panel.
-            if (mContentViewCore == null) {
-                createNewContentView();
-            }
+            if (mContentViewCore == null) createNewContentView();
 
             // NOTE(pedrosimonetti): Calling onShow() on the ContentViewCore will cause the page
             // to be rendered. This has a side effect of causing the page to be included in
             // your Web History (if enabled). For this reason, onShow() should only be called
             // when we know for sure the page will be seen by the user.
-            if (mContentViewCore != null) mContentViewCore.onShow();
+            if (mWebContents != null) mWebContents.onShow();
 
             mContentDelegate.onContentViewSeen();
         } else {
-            if (mContentViewCore != null) mContentViewCore.onHide();
+            if (mWebContents != null) mWebContents.onHide();
         }
 
         mContentDelegate.onVisibilityChanged(isVisible);
@@ -493,7 +490,7 @@
     }
 
     private WebContents getWebContents() {
-        return mContentViewCore != null ? mContentViewCore.getWebContents() : null;
+        return mWebContents;
     }
 
     void onSizeChanged(int width, int height) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 128a8c5..66f0357 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -815,14 +815,14 @@
         mSearchPanel.loadUrlInPanel(searchUrl);
         mDidStartLoadingResolvedSearchRequest = true;
 
-        // TODO(pedrosimonetti): If the user taps on a word and quickly after that taps on the
+        // TODO(donnd): If the user taps on a word and quickly after that taps on the
         // peeking Search Bar, the Search Content View will not be displayed. It seems that
-        // calling ContentViewCore.onShow() while it's being created has no effect. Need
+        // calling WebContents.onShow() while it's being created has no effect. Need
         // to coordinate with Chrome-Android folks to come up with a proper fix for this.
         // For now, we force the ContentView to be displayed by calling onShow() again
         // when a URL is being loaded. See: crbug.com/398206
-        if (mSearchPanel.isContentShowing() && getSearchPanelContentViewCore() != null) {
-            getSearchPanelContentViewCore().onShow();
+        if (mSearchPanel.isContentShowing() && getSearchPanelWebContents() != null) {
+            getSearchPanelWebContents().onShow();
         }
     }
 
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 65deac9..07b5b153 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
@@ -102,7 +102,7 @@
         }
 
         /**
-         * Disconnects from the remote process. Safe to call even if {@link connect()} returned
+         * Disconnects from the remote process. Safe to call even if {@link #connect} returned
          * false, or if the remote service died.
          */
         public void disconnect() {
@@ -133,7 +133,7 @@
         public final int uid;
         public final DisconnectCallback disconnectCallback;
         public final PostMessageHandler postMessageHandler;
-        public final Set<Uri> mLinkedUrls = new HashSet<>();
+        public final Set<Origin> mLinkedOrigins = new HashSet<>();
         public OriginVerifier originVerifier;
         public boolean mIgnoreFragments;
         public boolean lowConfidencePrediction;
@@ -382,7 +382,7 @@
     }
 
     public synchronized boolean validateRelationship(
-            CustomTabsSessionToken session, int relation, Uri origin, Bundle extras) {
+            CustomTabsSessionToken session, int relation, Origin origin, Bundle extras) {
         return validateRelationshipInternal(session, relation, origin, false);
     }
 
@@ -390,7 +390,7 @@
      * Validates the link between the client and the origin.
      */
     public synchronized void verifyAndInitializeWithPostMessageOriginForSession(
-            CustomTabsSessionToken session, Uri origin, @Relation int relation) {
+            CustomTabsSessionToken session, Origin origin, @Relation int relation) {
         validateRelationshipInternal(session, relation, origin, true);
     }
 
@@ -398,18 +398,18 @@
      * Can't be called on UI Thread.
      */
     private synchronized boolean validateRelationshipInternal(CustomTabsSessionToken session,
-            int relation, Uri origin, boolean initializePostMessageChannel) {
+            int relation, Origin origin, boolean initializePostMessageChannel) {
         SessionParams params = mSessionParams.get(session);
         if (params == null || TextUtils.isEmpty(params.getPackageName())) return false;
         OriginVerificationListener listener = null;
         if (initializePostMessageChannel) listener = params.postMessageHandler;
         params.originVerifier = new OriginVerifier(listener, params.getPackageName(), relation);
-        ThreadUtils.runOnUiThread(() -> { params.originVerifier.start(new Origin(origin)); });
+        ThreadUtils.runOnUiThread(() -> { params.originVerifier.start(origin); });
         if (relation == CustomTabsService.RELATION_HANDLE_ALL_URLS
                 && InstalledAppProviderImpl.isAppInstalledAndAssociatedWithOrigin(
                            params.getPackageName(), URI.create(origin.toString()),
                            mContext.getPackageManager())) {
-            params.mLinkedUrls.add(origin);
+            params.mLinkedOrigins.add(origin);
         }
         return true;
     }
@@ -433,11 +433,11 @@
         if (params == null) return false;
         String packageName = params.getPackageName();
         if (TextUtils.isEmpty(packageName)) return false;
-        boolean isAppAssociatedWithOrigin = params.mLinkedUrls.contains(url);
+        Origin origin = new Origin(url);
+        boolean isAppAssociatedWithOrigin = params.mLinkedOrigins.contains(origin);
         if (!isAppAssociatedWithOrigin) return false;
 
         // Split path from the given Uri to get only the origin before web->native verification.
-        Origin origin = new Origin(url);
         if (OriginVerifier.isValidOrigin(
                     packageName, origin, CustomTabsService.RELATION_HANDLE_ALL_URLS)) {
             return true;
@@ -637,9 +637,9 @@
      * @param origin Origin to verify
      */
     public synchronized boolean isFirstPartyOriginForSession(
-            CustomTabsSessionToken session, Uri origin) {
-        return OriginVerifier.isValidOrigin(getClientPackageNameForSession(session),
-                new Origin(origin), CustomTabsService.RELATION_USE_AS_ORIGIN);
+            CustomTabsSessionToken session, Origin origin) {
+        return OriginVerifier.isValidOrigin(getClientPackageNameForSession(session), origin,
+                CustomTabsService.RELATION_USE_AS_ORIGIN);
     }
 
     /** Tries to bind to a client to keep it alive, and returns true for success. */
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 4d3f344e..5970c3ef 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
@@ -50,6 +50,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.browserservices.BrowserSessionContentUtils;
+import org.chromium.chrome.browser.browserservices.Origin;
 import org.chromium.chrome.browser.browserservices.PostMessageHandler;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.init.ChainedTasks;
@@ -67,7 +68,6 @@
 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;
@@ -668,7 +668,7 @@
     }
 
     public boolean requestPostMessageChannel(CustomTabsSessionToken session,
-            Uri postMessageOrigin) {
+            Origin postMessageOrigin) {
         boolean success = requestPostMessageChannelInternal(session, postMessageOrigin);
         logCall("requestPostMessageChannel() with origin "
                 + (postMessageOrigin != null ? postMessageOrigin.toString() : ""), success);
@@ -676,7 +676,7 @@
     }
 
     private boolean requestPostMessageChannelInternal(final CustomTabsSessionToken session,
-            final Uri postMessageOrigin) {
+            final Origin postMessageOrigin) {
         if (!mWarmupHasBeenCalled.get()) return false;
         if (!isCallerForegroundOrSelf() && !BrowserSessionContentUtils.isActiveSession(session)) {
             return false;
@@ -711,7 +711,7 @@
      * @return The validated origin {@link Uri} for the given session's client.
      */
     protected Uri verifyOriginForSession(
-            CustomTabsSessionToken session, int clientUid, Uri origin) {
+            CustomTabsSessionToken session, int clientUid, Origin origin) {
         if (clientUid == Process.myUid()) return Uri.EMPTY;
         return null;
     }
@@ -738,7 +738,7 @@
     }
 
     public boolean validateRelationship(
-            CustomTabsSessionToken sessionToken, int relation, Uri origin, Bundle extras) {
+            CustomTabsSessionToken sessionToken, int relation, Origin origin, Bundle extras) {
         // Essential parts of the verification will depend on native code and will be run sync on UI
         // thread. Make sure the client has called warmup() beforehand.
         if (!mWarmupHasBeenCalled.get()) return false;
@@ -920,9 +920,9 @@
         Uri redirectEndpoint = intent.getParcelableExtra(REDIRECT_ENDPOINT_KEY);
         if (redirectEndpoint == null || !isValid(redirectEndpoint)) return;
 
-        String origin = GURLUtils.getOrigin(url);
+        Origin origin = new Origin(url);
         if (origin == null) return;
-        if (!mClientManager.isFirstPartyOriginForSession(session, Uri.parse(origin))) return;
+        if (!mClientManager.isFirstPartyOriginForSession(session, origin)) return;
 
         WarmupManager.getInstance().maybePreconnectUrlAndSubResources(
                 Profile.getLastUsedProfile(), redirectEndpoint.toString());
@@ -953,7 +953,7 @@
         // TODO(lizeb): Relax the restrictions.
         return ChromeBrowserInitializer.getInstance(mContext).hasNativeInitializationCompleted()
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_PARALLEL_REQUEST)
-                && mClientManager.isFirstPartyOriginForSession(session, referrer);
+                && mClientManager.isFirstPartyOriginForSession(session, new Origin(referrer));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
index ebd51d5..21a57c4b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
@@ -11,6 +11,7 @@
 import android.support.customtabs.CustomTabsService;
 import android.support.customtabs.CustomTabsSessionToken;
 
+import org.chromium.chrome.browser.browserservices.Origin;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 
@@ -78,7 +79,7 @@
     @Override
     protected boolean requestPostMessageChannel(CustomTabsSessionToken sessionToken,
             Uri postMessageOrigin) {
-        return mConnection.requestPostMessageChannel(sessionToken, postMessageOrigin);
+        return mConnection.requestPostMessageChannel(sessionToken, new Origin(postMessageOrigin));
     }
 
     @Override
@@ -91,7 +92,7 @@
     @Override
     protected boolean validateRelationship(
             CustomTabsSessionToken sessionToken, int relation, Uri origin, Bundle extras) {
-        return mConnection.validateRelationship(sessionToken, relation, origin, extras);
+        return mConnection.validateRelationship(sessionToken, relation, new Origin(origin), extras);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index f2443fb..2ca453b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -42,6 +42,7 @@
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.metrics.MemoryUma;
+import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
 import org.chromium.chrome.browser.upgrade.UpgradeActivity;
@@ -258,6 +259,7 @@
     }
 
     private final void onCreateInternal(Bundle savedInstanceState) {
+        UmaUtils.recordActivityStartTime();
         setIntent(validateIntent(getIntent()));
 
         @LaunchIntentDispatcher.Action
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
index 9a80a93..43806af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -23,10 +23,11 @@
 
     // All these values originate from SystemClock.uptimeMillis().
     private static long sApplicationStartTimeMs;
+    private static long sActivityStartTimeMs;
     private static long sForegroundStartTimeMs;
     private static long sBackgroundTimeMs;
 
-    // Event duration recorded from the |sApplicationStartTimeMs|.
+    // Event duration recorded from the |sActivityStartTimeMs|.
     private static long sFirstCommitTimeMs;
 
     /**
@@ -43,6 +44,10 @@
         sApplicationStartTimeMs = SystemClock.uptimeMillis();
     }
 
+    public static void recordActivityStartTime() {
+        sActivityStartTimeMs = SystemClock.uptimeMillis();
+    }
+
     /**
      * Record the time at which Chrome was brought to foreground.
      */
@@ -68,9 +73,10 @@
      */
     public static void registerFinishNavigation(boolean isTrackedPage) {
         if (!isRunningApplicationStart()) return;
+        assert sActivityStartTimeMs != 0;
 
         if (isTrackedPage && hasComeToForeground() && !hasComeToBackground()) {
-            sFirstCommitTimeMs = SystemClock.uptimeMillis() - sApplicationStartTimeMs;
+            sFirstCommitTimeMs = SystemClock.uptimeMillis() - sActivityStartTimeMs;
             RecordHistogram.recordLongTimesHistogram100(
                     "Startup.Android.Experimental.Cold.TimeToFirstNavigationCommit",
                     sFirstCommitTimeMs, TimeUnit.MILLISECONDS);
@@ -91,7 +97,7 @@
         if (hasComeToForeground() && !hasComeToBackground()) {
             RecordHistogram.recordLongTimesHistogram100(
                     "Startup.Android.Experimental.Cold.TimeToFirstContentfulPaint",
-                    firstContentfulPaintMs - sApplicationStartTimeMs, TimeUnit.MILLISECONDS);
+                    firstContentfulPaintMs - sActivityStartTimeMs, TimeUnit.MILLISECONDS);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
index 44cf0b5a..7bd8e2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
@@ -4,11 +4,11 @@
 
 package org.chromium.chrome.browser.signin;
 
-import android.app.Fragment;
-import android.app.FragmentManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
 import android.support.v7.app.AppCompatActivity;
 
 import org.chromium.base.Log;
@@ -51,7 +51,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.signin_activity);
 
-        FragmentManager fragmentManager = getFragmentManager();
+        FragmentManager fragmentManager = getSupportFragmentManager();
         Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);
         if (fragment == null) {
             fragment = new SigninFragment();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
index e7e5b80..11d9a8d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
@@ -5,11 +5,11 @@
 package org.chromium.chrome.browser.signin;
 
 import android.annotation.SuppressLint;
-import android.app.Fragment;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
+import android.support.v4.app.Fragment;
 import android.support.v7.content.res.AppCompatResources;
 import android.text.method.LinkMovementMethod;
 import android.view.LayoutInflater;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index cd383a38..bc4a731 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1268,7 +1268,7 @@
             loadIfNeeded();
             assert !isFrozen();
 
-            if (mContentViewCore != null) mContentViewCore.onShow();
+            if (getWebContents() != null) getWebContents().onShow();
 
             if (mTabUma != null) {
                 mTabUma.onShow(type, getTimestampMillis(),
@@ -1309,7 +1309,7 @@
             mIsHidden = true;
             updateInteractableState();
 
-            if (mContentViewCore != null) mContentViewCore.onHide();
+            if (getWebContents() != null) getWebContents().onHide();
 
             // Clean up any fullscreen state that might impact other tabs.
             if (mFullscreenManager != null) {
@@ -2611,7 +2611,7 @@
         if (mContentViewCore != null) {
             originalWidth = mContentView.getWidth();
             originalHeight = mContentView.getHeight();
-            mContentViewCore.onHide();
+            mContentViewCore.getWebContents().onHide();
         }
 
         Rect bounds = new Rect();
@@ -2634,7 +2634,7 @@
             nativeOnPhysicalBackingSizeChanged(mNativeTabAndroid,
                     newContentViewCore.getWebContents(), bounds.right, bounds.bottom);
         }
-        newContentViewCore.onShow();
+        newContentViewCore.getWebContents().onShow();
         setContentViewCore(newContentViewCore);
 
         destroyNativePageInternal(previousNativePage);
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
index b50f0f32..4155ddb9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
@@ -170,7 +170,7 @@
 <translation id="2498359688066513246">Ajuda i suggeriments </translation>
 <translation id="2501278716633472235">Enrere</translation>
 <translation id="2503472621226270518">Desplega el tauler de navegació</translation>
-<translation id="2512222046227390255">Emplenament automàtic de formularis</translation>
+<translation id="2512222046227390255">Emplena formularis automàticament</translation>
 <translation id="2526148617758225454">L'Economitzador de dades està activat. Gestioneu-lo a Configuració.</translation>
 <translation id="2532336938189706096">Visualització web</translation>
 <translation id="2536728043171574184">S'està mostrant una còpia sense connexió d'aquesta pàgina</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
index 31c7132..901be6f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
@@ -171,7 +171,7 @@
 <translation id="2498359688066513246">Bantuan &amp; masukan</translation>
 <translation id="2501278716633472235">Kembali</translation>
 <translation id="2503472621226270518">Luaskan panel navigasi</translation>
-<translation id="2512222046227390255">Formulir Isi-Otomatis</translation>
+<translation id="2512222046227390255">Formulir isi otomatis</translation>
 <translation id="2526148617758225454">Penghemat Kuota Internet aktif. Kelola di Setelan.</translation>
 <translation id="2532336938189706096">Tampilan Web</translation>
 <translation id="2536728043171574184">Melihat salinan offline halaman ini</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
index 7f9398e..16a7a91b 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
@@ -87,6 +87,7 @@
 <translation id="1709438864123551175">Экономия трафика</translation>
 <translation id="1718835860248848330">Последний час</translation>
 <translation id="1729516292547892356">Чтобы просматривать контент в режиме виртуальной реальности, обновите Google VR-сервисы</translation>
+<translation id="1733116627827457509"><ph name="FILE_SIZE" />. Обновление <ph name="TIME_SINCE_UPDATE" /></translation>
 <translation id="1749561566933687563">Синхронизируйте закладки</translation>
 <translation id="17513872634828108">Открытые вкладки</translation>
 <translation id="1756600373018374892">Используйте эту кнопку для быстрого доступа к вкладкам.</translation>
@@ -784,6 +785,7 @@
 <translation id="8200772114523450471">Возобновить</translation>
 <translation id="8209050860603202033">Открыть изображение</translation>
 <translation id="8220488350232498290">Скачанные файлы: <ph name="GIGABYTES" /> ГБ</translation>
+<translation id="8249310407154411074">Переместить в начало</translation>
 <translation id="8250920743982581267">Документы</translation>
 <translation id="8260126382462817229">Снова войдите в аккаунт</translation>
 <translation id="8261506727792406068">Удалить</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
index e6f5f879..bd305a0 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
@@ -171,7 +171,7 @@
 <translation id="2498359688066513246">Pomoč in povratne informacije</translation>
 <translation id="2501278716633472235">Nazaj</translation>
 <translation id="2503472621226270518">Razširi navigacijsko ploščo</translation>
-<translation id="2512222046227390255">Obrazci s samodejnim izpolnjevanjem</translation>
+<translation id="2512222046227390255">Samodejno izpolnjevanje obrazcev</translation>
 <translation id="2526148617758225454">Varčevanje s podatki je vklopljeno. Upravljate ga lahko v nastavitvah.</translation>
 <translation id="2532336938189706096">Spletni pogled</translation>
 <translation id="2536728043171574184">Ogled kopije te strani za način brez povezave.</translation>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
index 6f4851e..b9174f80 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -59,7 +59,7 @@
     private boolean mShouldUseHttps;
     private boolean mIsOnline = true;
 
-    private boolean mDidEverCallContentViewCoreOnShow;
+    private boolean mDidEverCallWebContentsOnShow;
 
     private class ContentsObserver extends WebContentsObserver {
         private boolean mIsVisible;
@@ -75,7 +75,7 @@
         @Override
         public void wasShown() {
             mIsVisible = true;
-            mDidEverCallContentViewCoreOnShow = true;
+            mDidEverCallWebContentsOnShow = true;
         }
 
         @Override
@@ -489,11 +489,11 @@
     }
 
     /**
-     * @return Whether onShow() was ever called for the current {@code ContentViewCore}.
+     * @return Whether onShow() was ever called for the current {@code WebContents}.
      */
     @VisibleForTesting
-    boolean didEverCallContentViewCoreOnShow() {
-        return mDidEverCallContentViewCoreOnShow;
+    boolean didEverCallWebContentsOnShow() {
+        return mDidEverCallWebContentsOnShow;
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 0e76087..1e996a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -557,10 +557,10 @@
     }
 
     /**
-     * Asserts that the Panel's ContentViewCore onShow() method was never called.
+     * Asserts that the Panel's WebContents.onShow() method was never called.
      */
-    private void assertNeverCalledContentViewCoreOnShow() {
-        Assert.assertFalse(mFakeServer.didEverCallContentViewCoreOnShow());
+    private void assertNeverCalledWebContentsOnShow() {
+        Assert.assertFalse(mFakeServer.didEverCallWebContentsOnShow());
     }
 
     /**
@@ -569,7 +569,7 @@
     private void assertContentViewCoreCreatedButNeverMadeVisible() {
         assertContentViewCoreCreated();
         Assert.assertFalse(isContentViewCoreVisible());
-        assertNeverCalledContentViewCoreOnShow();
+        assertNeverCalledWebContentsOnShow();
     }
 
     /**
@@ -2541,7 +2541,7 @@
 
         // Now simulate a long press, leaving the Panel peeking.
         simulateLongPressSearch("resolution");
-        assertNeverCalledContentViewCoreOnShow();
+        assertNeverCalledWebContentsOnShow();
         Assert.assertEquals(1, mFakeServer.getLoadedUrlCount());
 
         // Expanding the Panel should load and display the new search.
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 f87baa1..585dc7c 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
@@ -181,7 +181,7 @@
             public void run() {
                 // With no prepopulated origins, this verification should fail.
                 cm.verifyAndInitializeWithPostMessageOriginForSession(
-                        mSession, Uri.parse(URL), CustomTabsService.RELATION_USE_AS_ORIGIN);
+                        mSession, new Origin(URL), CustomTabsService.RELATION_USE_AS_ORIGIN);
                 Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
                 // If there is a prepopulated origin, we should get a synchronous verification.
@@ -189,7 +189,7 @@
                         ContextUtils.getApplicationContext().getPackageName(), new Origin(URL),
                         CustomTabsService.RELATION_USE_AS_ORIGIN);
                 cm.verifyAndInitializeWithPostMessageOriginForSession(
-                        mSession, Uri.parse(URL), CustomTabsService.RELATION_USE_AS_ORIGIN);
+                        mSession, new Origin(URL), CustomTabsService.RELATION_USE_AS_ORIGIN);
             }
         });
 
@@ -223,21 +223,23 @@
         // Should always start with no origin.
         Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
+        Origin origin = new Origin(URL);
+
         // With no prepopulated origins, this verification should fail.
         cm.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(URL), CustomTabsService.RELATION_USE_AS_ORIGIN);
+                mSession, origin, CustomTabsService.RELATION_USE_AS_ORIGIN);
         Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
         ThreadUtils.runOnUiThreadBlocking(() -> {
             // Prepopulated origins should depend on the relation used.
             OriginVerifier.addVerifiedOriginForPackage(
-                    ContextUtils.getApplicationContext().getPackageName(), new Origin(URL),
+                    ContextUtils.getApplicationContext().getPackageName(), origin,
                     CustomTabsService.RELATION_HANDLE_ALL_URLS);
             // This uses CustomTabsService.RELATION_USE_AS_ORIGIN by default.
-            Assert.assertFalse(cm.isFirstPartyOriginForSession(mSession, Uri.parse(URL)));
+            Assert.assertFalse(cm.isFirstPartyOriginForSession(mSession, origin));
         });
 
         cm.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(URL), CustomTabsService.RELATION_HANDLE_ALL_URLS);
+                mSession, origin, CustomTabsService.RELATION_HANDLE_ALL_URLS);
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
             Uri verifiedOrigin = cm.getPostMessageOriginForSessionForTesting(mSession);
@@ -261,19 +263,19 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                Uri uri = Uri.parse(HTTP_URL);
+                Origin origin = new Origin(HTTP_URL);
                 // With no prepopulated origins, this verification should fail.
                 cm.verifyAndInitializeWithPostMessageOriginForSession(
-                        mSession, uri, CustomTabsService.RELATION_USE_AS_ORIGIN);
+                        mSession, origin, CustomTabsService.RELATION_USE_AS_ORIGIN);
                 Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
                 // Even if there is a prepopulated origin, non-https origins should get an early
                 // return with false.
                 OriginVerifier.addVerifiedOriginForPackage(
-                        ContextUtils.getApplicationContext().getPackageName(), new Origin(uri),
+                        ContextUtils.getApplicationContext().getPackageName(), origin,
                         CustomTabsService.RELATION_USE_AS_ORIGIN);
                 cm.verifyAndInitializeWithPostMessageOriginForSession(
-                        mSession, uri, CustomTabsService.RELATION_USE_AS_ORIGIN);
+                        mSession, origin, CustomTabsService.RELATION_USE_AS_ORIGIN);
                 Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
             }
         });
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 9f04789..a95c5103 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -72,6 +72,8 @@
 #define IDC_RESTORE_WINDOW              34052
 #endif
 
+#define IDC_OPEN_IN_PWA_WINDOW          34053
+
 // Hosted app commands
 #define IDC_COPY_URL                    34060
 #define IDC_OPEN_IN_CHROME              34061
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 6e995c1..6d8e935 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -868,6 +868,9 @@
           <message name="IDS_SITE_SETTINGS" desc="The text label of the Site Settings menu item for the Hosted App app menu">
             &amp;Site settings
           </message>
+          <message name="IDS_OPEN_IN_APP_WINDOW" desc="The text label of the menu item for moving the current tab to a standalone app window">
+            Open in <ph name="APP">$1<ex>Gmail App</ex></ph>
+          </message>
         </if>
         <if expr="use_titlecase">
           <message name="IDS_NEW_TAB" desc="In Title Case: The text label of a menu item for opening a new tab">
@@ -939,6 +942,9 @@
           <message name="IDS_SITE_SETTINGS" desc="In Title Case: The text label of the Site Settings menu item for the Hosted App app menu">
             &amp;Site Settings
           </message>
+          <message name="IDS_OPEN_IN_APP_WINDOW" desc="In Title Case: The text label of the menu item for moving the current tab to a standalone app window">
+            Open in <ph name="APP">$1<ex>Gmail App</ex></ph>
+          </message>
         </if>
       </if>
 
diff --git a/chrome/app/resources/chromium_strings_ru.xtb b/chrome/app/resources/chromium_strings_ru.xtb
index 897a5e7..a02b836 100644
--- a/chrome/app/resources/chromium_strings_ru.xtb
+++ b/chrome/app/resources/chromium_strings_ru.xtb
@@ -17,6 +17,8 @@
 <translation id="1668054258064581266">После удаления вашего аккаунта из Chromium может понадобиться перезагрузить открытые вкладки, чтобы изменения вступили в силу.</translation>
 <translation id="1688750314291223739">Настройте синхронизацию, чтобы сохранить в облаке персонализированные функции браузера и получить к ним доступ из Chromium с любого компьютера.</translation>
 <translation id="1708666629004767631">Доступна новая, еще более быстрая версия Chromium.</translation>
+<translation id="1716051742506968">{0,plural, =0{Доступно обновление Chromium}=1{Доступно обновление Chromium}one{Обновление Chromium доступно # день}few{Обновление Chromium доступно # дня}many{Обновление Chromium доступно # дней}other{Обновление Chromium доступно # дня}}</translation>
+<translation id="1766096484055239003">Администратор требует перезапустить Chromium для установки обновления</translation>
 <translation id="1774152462503052664">Разрешить Chromium работать в фоновом режиме</translation>
 <translation id="1779356040007214683">Чтобы обеспечить безопасность ваших данных, некоторые расширения Chromium были отключены, так как <ph name="IDS_EXTENSION_WEB_STORE_TITLE" /> не содержит сведений о них, то есть эти компоненты могли быть установлены без вашего ведома.</translation>
 <translation id="1808667845054772817">Переустановить Chromium</translation>
@@ -27,6 +29,7 @@
 <translation id="1967743265616885482">Известно, что модуль с таким названием конфликтует с Chromium.</translation>
 <translation id="2008474315282236005">С устройства будет удален 1 объект. Чтобы восстановить данные позже, войдите в Chromium как <ph name="USER_EMAIL" />.</translation>
 <translation id="2077129598763517140">Использовать аппаратное ускорение (при наличии)</translation>
+<translation id="2117378023188580026">Администратор просит перезапустить Chromium для установки обновления</translation>
 <translation id="2119636228670142020">О &amp;Chromium OS</translation>
 <translation id="2158734852934720349">Лицензии Chromium OS на ПО с открытым исходным кодом</translation>
 <translation id="2241627712206172106">Если, кроме вас, компьютером пользуется кто-то ещё, например родные или друзья, они тоже смогут настроить Chromium на свой вкус.</translation>
@@ -102,6 +105,7 @@
 <translation id="4488554488975128561">Вы можете автоматически отправлять системную информацию и контент страниц в Google, чтобы помочь улучшить распознавание опасных приложений и сайтов. Давайте вместе сделаем Chromium ещё удобнее и безопаснее!</translation>
 <translation id="4567424176335768812">Вы вошли с помощью аккаунта <ph name="USER_EMAIL_ADDRESS" />. Ваши закладки, история и другие настройки теперь доступны на всех устройствах, где вы используете этот аккаунт.</translation>
 <translation id="459535195905078186">Приложения Chromium</translation>
+<translation id="4604377857208775795">{0,plural, =1{Chromium перезапустится через 1 минуту}one{Chromium перезапустится через # минуту}few{Chromium перезапустится через # минуты}many{Chromium перезапустится через # минут}other{Chromium перезапустится через # минуты}}</translation>
 <translation id="4621240073146040695">Чтобы завершить обновление, перезапустите Chromium.</translation>
 <translation id="4677944499843243528">Скорее всего, профиль используется другим процессом Chromium (<ph name="PROCESS_ID" />) на другом компьютере (<ph name="HOST_NAME" />). Во избежание сбоев профиль был заблокирован. Если вы уверены, что профиль не используется другими процессами, разблокируйте его и перезапустите Chromium.</translation>
 <translation id="469338717132742108">Справка Chromium OS</translation>
@@ -160,6 +164,7 @@
 <translation id="6485906693002546646">Для синхронизации данных Chromium используется аккаунт <ph name="PROFILE_EMAIL" />. Изменить параметры синхронизации или отключить аккаунт можно в <ph name="SETTINGS_LINK" />.</translation>
 <translation id="6510925080656968729">Удаление Chromium</translation>
 <translation id="6598877126913850652">Открыть настройки уведомлений Chromium</translation>
+<translation id="6664239887951090350">{0,plural, =0{Chromium перезапускается}=1{Chromium перезапустится через 1 секунду}one{Chromium перезапустится через # секунду}few{Chromium перезапустится через # секунды}many{Chromium перезапустится через # секунд}other{Chromium перезапустится через # секунды}}</translation>
 <translation id="6676384891291319759">Доступ в Интернет</translation>
 <translation id="6717134281241384636">Ваш профиль не может использоваться, поскольку он от более новой версии Chromium.
 
@@ -201,6 +206,7 @@
 <translation id="761356813943268536">Chromium использует камеру и микрофон.</translation>
 <translation id="7617377681829253106">Chromium становится все лучше</translation>
 <translation id="7686590090926151193">Chromium не является браузером по умолчанию.</translation>
+<translation id="7689606757190482937">Синхронизируйте данные Chromium на всех устройствах</translation>
 <translation id="7729447699958282447">Chromium не удалось синхронизировать данные, поскольку служба Sync недоступна для вашего домена.</translation>
 <translation id="7745317241717453663">Данные о работе в браузере будут удалены с устройства. Чтобы восстановить их позже, войдите в Chromium как <ph name="USER_EMAIL" />.</translation>
 <translation id="7747138024166251722">Программе установки не удалось создать временный каталог. Возможно, у вас нет прав на установку приложений или недостаточно места на диске.</translation>
@@ -219,6 +225,7 @@
 <translation id="8222496066431494154">Установите Chromium на телефон. Мы отправим SMS на номер, указанный в вашем аккаунте: <ph name="PHONE_NUMBER" />.</translation>
 <translation id="8269379391216269538">Сделайте Chromium лучше</translation>
 <translation id="8290862415967981663">Chromium заблокировал этот файл как потенциально опасный.</translation>
+<translation id="8330519371938183845">Войдите, чтобы синхронизировать данные Chromium на всех устройствах</translation>
 <translation id="8340674089072921962">Адрес <ph name="USER_EMAIL_ADDRESS" /> уже использовался в Chromium</translation>
 <translation id="8453117565092476964">Установочный архив поврежден. Скачайте Chromium ещё раз.</translation>
 <translation id="8493179195440786826">Версия Chromium устарела</translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 41f7f54..996d323 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -969,7 +969,7 @@
 <translation id="2508428939232952663">Compte de Google Play Store</translation>
 <translation id="2509495747794740764">El valor de l'escala ha d'oscil·lar entre 10 i 200.</translation>
 <translation id="2509566264613697683">8x</translation>
-<translation id="2512222046227390255">Emplenament automàtic de formularis</translation>
+<translation id="2512222046227390255">Emplena formularis automàticament</translation>
 <translation id="2515586267016047495">Alt</translation>
 <translation id="2517472476991765520">Cerca</translation>
 <translation id="2518024842978892609">Utilitzar els certificats de client</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 8a25b9b2..1f181d3 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -624,6 +624,7 @@
 <translation id="1944921356641260203">અપડેટ મળ્યું</translation>
 <translation id="1951615167417147110">એક પૃષ્ઠ સ્ક્રોલ કરો</translation>
 <translation id="1956050014111002555">ફાઇલમાં બહુવિધ પ્રમાણપત્રો રહેલા છે, તેમાંનાં કોઈપણ આયાત કરેલા નથી:</translation>
+<translation id="1956390763342388273">આનાથી "<ph name="FOLDER_PATH" />"માંથી બધી ફાઇલો અપલોડ થશે. જો તમે સાઇટ પર વિશ્વાસ કરતા હો, તો જ આ કરશો.</translation>
 <translation id="1962233722219655970">આ પૃષ્ઠ મૂળ ક્લાયન્ટ એપ્લિકેશનનો ઉપયોગ કરે છે જે તમારા કમ્પ્યુટર પર કામ કરતી નથી.</translation>
 <translation id="1962969542251276847">સ્ક્રીન લૉક કરો</translation>
 <translation id="1963227389609234879">બધું દૂર કરો</translation>
@@ -836,6 +837,7 @@
 <translation id="2294358108254308676">શું તમે <ph name="PRODUCT_NAME" /> ઇન્સ્ટોલ કરવા માંગો છો?</translation>
 <translation id="2296019197782308739">EAP પદ્ધતિ:</translation>
 <translation id="2297705863329999812">પ્રિન્ટર શોધો</translation>
+<translation id="2300383962156589922"><ph name="APP_NAME" />ને કસ્ટમાઇઝ કરો અને નિયંત્રિત કરો</translation>
 <translation id="2301382460326681002">એક્સ્ટેંશન રૂટ ડાયરેક્ટરી અમાન્ય છે.</translation>
 <translation id="2302685579236571180">છૂપામાં જાઓ </translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" એ અતિરિક્ત પરવાનગીઓની વિનંતી કરી છે.</translation>
@@ -1227,7 +1229,7 @@
 <translation id="2867768963760577682">પિન કરેલા ટૅબ તરીકે ખોલો</translation>
 <translation id="2868746137289129307">આ એક્સ્ટેન્શન જૂનું થઈ ગયું છે અને એન્ટરપ્રાઇસ નીતિ દ્વારા અક્ષમ થયું છે. જ્યારે એક નવું સંસ્કરણ ઉપલબ્ધ થાય ત્યારે તે આપમેળે સક્ષમ થઈ શકે છે.</translation>
 <translation id="2870560284913253234">સાઇટ</translation>
-<translation id="2870909136778269686">અપડેટ થઈ રહ્યું છે...</translation>
+<translation id="2870909136778269686">અપડેટ કરી રહ્યાં છીએ...</translation>
 <translation id="2871813825302180988">આ એકાઉન્ટ પહેલાથી જ આ ઉપકરણ પર ઉપયોગમાં લેવાઈ રહ્યું છે.</translation>
 <translation id="2872353916818027657">પ્રાથમિક મૉનિટર સ્વેપ કરો</translation>
 <translation id="287286579981869940"><ph name="PROVIDER_NAME" /> ઉમેરો...</translation>
@@ -1324,6 +1326,7 @@
 <translation id="3012917896646559015">તમારા કમ્પ્યુટરને સમારકામ સગવડ પર મોકલવા માટે તુરંત તમારા હાર્ડવેર નિર્માતાનો સંપર્ક કરો.</translation>
 <translation id="3013291976881901233">MIDI ઉપકરણો</translation>
 <translation id="3014095112974898292">અન્ય વિનંતીઓ પૂર્ણ થવાની રાહ જોઈ રહ્યું છે...</translation>
+<translation id="3015639418649705390">હમણાં ફરીથી લૉન્ચ કરો</translation>
 <translation id="3015992588037997514">શું આ કોડ તમારી Chromebox સ્ક્રીન પર દેખાયો?</translation>
 <translation id="3016641847947582299">ઘટક અપડેટ કર્યો</translation>
 <translation id="3016780570757425217">તમારું સ્થાન જાણો</translation>
@@ -2199,6 +2202,7 @@
 <translation id="4430369329743628066">બુકમાર્ક ઉમેરાયો</translation>
 <translation id="443454694385851356">લેગસી (અસુરક્ષિત)</translation>
 <translation id="443464694732789311">ચાલુ રાખો</translation>
+<translation id="443475966875174318">અસંગત ઍપ્લિકેશનોને અપડેટ કરો અથવા કાઢી નાખો</translation>
 <translation id="4439318412377770121">શું તમે Google મેઘ ઉપકરણો પર <ph name="DEVICE_NAME" /> ને નોંધાવવા માગો છો?</translation>
 <translation id="4441124369922430666">શું જ્યારે મશીન ચાલુ થાય ત્યારે તમે આ એપ્લિકેશનને આપમેળે પ્રારંભ કરવા માંગો છો?</translation>
 <translation id="444134486829715816">વિસ્તૃત કરો...</translation>
@@ -2381,6 +2385,7 @@
 <translation id="473775607612524610">અપડેટ કરો</translation>
 <translation id="474217410105706308">ટૅબ મ્યૂટ કરો</translation>
 <translation id="4742746985488890273">શેલ્ફ પર પિન કરો</translation>
+<translation id="4743260470722568160"><ph name="BEGIN_LINK" />ઍપ્લિકેશનો કેવી રીતે અપલોડ કરવી તે જાણો<ph name="END_LINK" /></translation>
 <translation id="4744574733485822359">તમારું ડાઉનલોડ પૂર્ણ થયું છે</translation>
 <translation id="4746971725921104503">એવું લાગે છે કે તમે પહેલાંથી જ તે નામના વપરાશકર્તાનું સંચાલન કરી રહ્યાં છે. શું તમે <ph name="LINK_START" />આ ઉપકરણ પર <ph name="USER_DISPLAY_NAME" /> ને આયાત<ph name="LINK_END" /> કરવા માગો છો?</translation>
 <translation id="4748762018725435655">Chrome વેબ દુકાનમાંથી એક્સ્ટેન્શન આવશ્યક છે</translation>
@@ -3192,6 +3197,7 @@
     <ph name="BEGIN_PARAGRAPH2" />તમે આને કોઈપણ સમયે Android ઍપ્લિકેશનોની સેટિંગ્સમાં ચાલુ અથવા બંધ કરી શકો છો. આ સિસ્ટમ અપડેટ્સ અને સુરક્ષા જેવી આવશ્યક સેવાઓ પ્રાપ્ત કરવા માટે તેને જરૂર હોય એવી માહિતી મોકલવા માટેની તમારા ઉપકરણની ક્ષમતાને પ્રભાવિત કરતું નથી.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="5990386583461751448">અનુવાદિત</translation>
 <translation id="5991049340509704927">મૅગ્નિફાઇ</translation>
+<translation id="599131315899248751">{NUM_APPLICATIONS,plural, =1{તમે વેબ બ્રાઉઝ કરતા રહી શકો તેની ખાતરી કરવા માટે, તમારા વ્યવસ્થાપકને આ ઍપ્લિકેશન કાઢી નાખવાનું કહો.}one{તમે વેબ બ્રાઉઝ કરતા રહી શકો તેની ખાતરી કરવા માટે, તમારા વ્યવસ્થાપકને આ ઍપ્લિકેશનો કાઢી નાખવાનું કહો.}other{તમે વેબ બ્રાઉઝ કરતા રહી શકો તેની ખાતરી કરવા માટે, તમારા વ્યવસ્થાપકને આ ઍપ્લિકેશનો કાઢી નાખવાનું કહો.}}</translation>
 <translation id="5993332328670040093">ડેટા વપરાશનું હવેથી માપન કરવામાં આવશે નહિ.</translation>
 <translation id="600424552813877586">અમાન્ય ઍપ્લિકેશન.</translation>
 <translation id="6005695835120147974">મીડિયા રાઉટર</translation>
@@ -3847,6 +3853,7 @@
 <translation id="7040138676081995583">આની સાથે ખોલો...</translation>
 <translation id="7040230719604914234">ઓપરેટર</translation>
 <translation id="7042418530779813870">પેસ્ટ&amp; કરો અને શોધો</translation>
+<translation id="7043108582968290193">થઈ ગયું! કોઈ અસંગત ઍપ્લિકેશન મળી નથી.</translation>
 <translation id="7049293980323620022">ફાઇલ રાખીએ?</translation>
 <translation id="7051943809462976355">માઉસ માટે શોધી રહ્યું છે...</translation>
 <translation id="7052237160939977163">પ્રદર્શન ટ્રેસ ડેટા મોકલો</translation>
@@ -4017,6 +4024,7 @@
 <translation id="7328867076235380839">અમાન્ય મિશ્રણ</translation>
 <translation id="7329154610228416156">સાઇન ઇન નિષ્ફળ થયું કારણ કે તે બિન-સુરક્ષિત URL (<ph name="BLOCKED_URL" />) નો ઉપયોગ કરવા માટે ગોઠવાયેલું હતું. કૃપા કરીને તમારા વ્યવસ્થાપકનો સંપર્ક કરો.</translation>
 <translation id="7334190995941642545">Smart Lock હાલમાં અનુપલબ્ધ છે. કૃપા કરીને પછીથી ફરી પ્રયાસ કરો.</translation>
+<translation id="7334274148831027933">ડૉક કરેલ બૃહદદર્શક ચાલુ કરો</translation>
 <translation id="7339763383339757376">PKCS #7, સિંગલ પ્રમાણપત્ર</translation>
 <translation id="7339785458027436441">લખતી વખતે જોડણી તપાસો</translation>
 <translation id="7339898014177206373">નવી વિંડો</translation>
@@ -4389,6 +4397,7 @@
 <translation id="7912080627461681647">સર્વર પર તમારો પાસવર્ડ બદલાઈ ગયો છે. કૃપા કરી સાઇન આઉટ કરો પછી ફરીથી સાઇન ઇન કરો.</translation>
 <translation id="7912883689016444961">મોબાઇલ નેટવર્કને ગોઠવો</translation>
 <translation id="7915471803647590281">કૃપા કરીને પ્રતિસાદ મોકલતા પહેલા શું થઈ રહ્યું છે તે અમને કહો.</translation>
+<translation id="792514962475806987">ડૉક કરેલ ઝૂમ લેવલ:</translation>
 <translation id="7925247922861151263">AAA તપાસ નિષ્ફળ</translation>
 <translation id="7925285046818567682"><ph name="HOST_NAME" /> ની પ્રતીક્ષા કરે છે...</translation>
 <translation id="7925686952655276919">સમન્વયન માટે ડેટા માહિતીની ઉપયોગ કરશો નહીં</translation>
@@ -4765,6 +4774,7 @@
 <translation id="8546541260734613940">[*.]example.com</translation>
 <translation id="854655314928502177">વેબ પ્રોક્સી સ્વતઃ શોધ URL:</translation>
 <translation id="8546930481464505581">ટચ બારને કસ્ટમાઇઝ કરો</translation>
+<translation id="8547013269961688403">પૂર્ણસ્ક્રીન બૃહદદર્શક ચાલુ કરો</translation>
 <translation id="85486688517848470">ટોચની-પંક્તિ કીની વર્તણૂંક બદલવા માટે શોધ કી દબાવી રાખો</translation>
 <translation id="855081842937141170">ટૅબ પિન કરો</translation>
 <translation id="8551388862522347954">લાઇસેંસીસ</translation>
@@ -4819,6 +4829,7 @@
 <translation id="8642947597466641025">ટેક્સ્ટ મોટો કરો</translation>
 <translation id="8647834505253004544">વેબ સરનામું માન્ય નથી</translation>
 <translation id="8648252583955599667"><ph name="GET_HELP_LINK" /> અથવા <ph name="RE_SCAN_LINK" /></translation>
+<translation id="8650543407998814195">જો કે તમે હવે તમારી જૂની પ્રોફાઇલ ઍક્સેસ કરી શકતા નથી, છતાં તમે તેને કાઢી નાખી શકો છો.</translation>
 <translation id="8651585100578802546">આ પૃષ્ઠ ફરીથી લોડ કરવા દબાણ કરો</translation>
 <translation id="8652400352452647993">પૅક એક્સટેન્શન ભૂલ</translation>
 <translation id="8652487083013326477">પૃષ્ઠ રેંજ રેડિઓ બટન</translation>
@@ -4895,7 +4906,9 @@
 <translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ને બદલે <ph name="PROTOCOL" /> લિંક્સ ખોલો</translation>
 <translation id="8737709691285775803">શિલ</translation>
 <translation id="8741316211671074806">ચિત્ર-માં-ચિત્ર</translation>
+<translation id="8743390665131937741">પૂર્ણસ્ક્રીન ઝૂમ લેવલ:</translation>
 <translation id="8743864605301774756">1 કલાક પહેલા અપડેટ કર્યું</translation>
+<translation id="874689135111202667">{0,plural, =1{આ સાઇટ પર એક ફાઇલ અપલોડ કરીએ?}one{આ સાઇટ પર # ફાઇલો અપલોડ કરીએ?}other{આ સાઇટ પર # ફાઇલો અપલોડ કરીએ?}}</translation>
 <translation id="8749863574775030885">અજાણ્યા વિક્રેતા પાસેથી USB ઉપકરણો ઍક્સેસ કરો</translation>
 <translation id="8754200782896249056">&lt;p&gt;જ્યારે સમર્થિત ડેસ્કટૉપ વાતાવરણની અંતર્ગત <ph name="PRODUCT_NAME" /> ચલાવી રહ્યા હોય, ત્યારે સિસ્ટમ પ્રોક્સી સેટિંગ્સ ઉપયોગમાં લેવાશે. તેમ છતાં, ક્યાં તો તમારી સિસ્ટમ સમર્થિત નથી અથવા તમારી સિસ્ટમ ગોઠવણીને લોંચ કરવામાં કોઈ સમસ્યા છે.&lt;/p&gt;
 
@@ -5200,6 +5213,7 @@
 <translation id="960719561871045870">ઓપરેટર કોડ</translation>
 <translation id="960987915827980018">લગભગ 1 કલાક બાકી</translation>
 <translation id="962802172452141067">બુકમાર્ક ફોલ્ડર વૃક્ષ</translation>
+<translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{ઍપ્લિકેશન}one{ઍપ્લિકેશનો}other{ઍપ્લિકેશનો}}</translation>
 <translation id="968000525894980488">Google Play સેવાઓ ચાલુ કરો.</translation>
 <translation id="968174221497644223">ઍપ્લિકેશન કેશ</translation>
 <translation id="969096075394517431">ભાષાઓ બદલો</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 4bfbe81..435a9012 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -971,7 +971,7 @@
 <translation id="2508428939232952663">Akun Google Play Store</translation>
 <translation id="2509495747794740764">Jumlah skala harus berupa angka antara 10 dan 200.</translation>
 <translation id="2509566264613697683">8x</translation>
-<translation id="2512222046227390255">Formulir Isi-Otomatis</translation>
+<translation id="2512222046227390255">Formulir isi otomatis</translation>
 <translation id="2515586267016047495">Alt</translation>
 <translation id="2517472476991765520">Pindai</translation>
 <translation id="2518024842978892609">Gunakan sertifikat klien Anda</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index 900a892..0c934929 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -625,6 +625,7 @@
 <translation id="1944921356641260203">נמצא עדכון</translation>
 <translation id="1951615167417147110">גלול מעלה דף אחד</translation>
 <translation id="1956050014111002555">הקובץ הכיל אישורים מרובים שאף אחד מהם לא יובא:</translation>
+<translation id="1956390763342388273">הפעולה הזו תעלה את כל הקבצים מ-"<ph name="FOLDER_PATH" />". יש לעשות זאת רק אם סומכים על האתר.</translation>
 <translation id="1962233722219655970">‏דף זה משתמש ביישום Native Client שאינו פועל במחשב שלך.</translation>
 <translation id="1962969542251276847">נעל מסך</translation>
 <translation id="1963227389609234879">הסר הכל</translation>
@@ -837,6 +838,7 @@
 <translation id="2294358108254308676">האם ברצונך להתקין את <ph name="PRODUCT_NAME" />?</translation>
 <translation id="2296019197782308739">‏שיטת EAP:</translation>
 <translation id="2297705863329999812">חפש מדפסות</translation>
+<translation id="2300383962156589922">התאמה אישית ושליטה ב-<ph name="APP_NAME" /></translation>
 <translation id="2301382460326681002">ספריית הבסיס של ההרחבה אינה חוקית.</translation>
 <translation id="2302685579236571180">גלוש בסתר</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" ביקש אישורים נוספים.</translation>
@@ -1325,6 +1327,7 @@
 <translation id="3012917896646559015">צור קשר עם יצרן החומרה באופן מיידי כדי לשלוח את המחשב לתיקון.</translation>
 <translation id="3013291976881901233">‏התקני MIDI</translation>
 <translation id="3014095112974898292">ממתין להשלמת הבקשות האחרות...</translation>
+<translation id="3015639418649705390">הפעלה מחדש עכשיו</translation>
 <translation id="3015992588037997514">‏האם קוד זה מופיע במסך ה-Chromebox שלך?</translation>
 <translation id="3016641847947582299">הרכיב עודכן</translation>
 <translation id="3016780570757425217">לדעת מה המיקום שלך</translation>
@@ -2199,6 +2202,7 @@
 <translation id="4430369329743628066">הסימנייה נוספה</translation>
 <translation id="443454694385851356">דור קודם (לא מאובטח)</translation>
 <translation id="443464694732789311">המשך</translation>
+<translation id="443475966875174318">עדכון או הסרה של אפליקציות לא תואמות</translation>
 <translation id="4439318412377770121">‏האם ברצונך לרשום את <ph name="DEVICE_NAME" /> ל-Google Cloud Devices?</translation>
 <translation id="4441124369922430666">האם ברצונך להפעיל יישום זה באופן אוטומטי בעת הפעלת המחשב?</translation>
 <translation id="444134486829715816">הרחב...</translation>
@@ -2381,6 +2385,7 @@
 <translation id="473775607612524610">עדכן</translation>
 <translation id="474217410105706308">השתק כרטיסייה</translation>
 <translation id="4742746985488890273">הצמד למדף</translation>
+<translation id="4743260470722568160"><ph name="BEGIN_LINK" />איך לעדכן אפליקציות<ph name="END_LINK" /></translation>
 <translation id="4744574733485822359">ההורדה הסתיימה</translation>
 <translation id="4746971725921104503">נראה שאתה כבר מנהל משתמש בשם הזה. האם רצית <ph name="LINK_START" />לייבא את <ph name="USER_DISPLAY_NAME" /> אל המכשיר הזה<ph name="LINK_END" />?</translation>
 <translation id="4748762018725435655">‏דרוש תוסף מחנות האינטרנט של Chrome</translation>
@@ -3192,6 +3197,7 @@
     <ph name="BEGIN_PARAGRAPH2" />ניתן להפעיל או להשבית את התכונה בכל עת דרך הגדרות האפליקציות ל-Android. הפעלה או השבתה של התכונה לא ישפיעו על היכולת של המכשיר לשלוח את המידע הנדרש כדי לקבל שירותים חיוניים כגון עדכוני מערכת ושירותי אבטחה.<ph name="END_PARAGRAPH2" /></translation>
 <translation id="5990386583461751448">מתורגם</translation>
 <translation id="5991049340509704927">הגדל</translation>
+<translation id="599131315899248751">{NUM_APPLICATIONS,plural, =1{כדי לוודא שאפשר להמשיך לגלוש באינטרנט, צריך לבקש ממנהל המערכת להסיר את האפליקציה הזו.}two{כדי לוודא שאפשר להמשיך לגלוש באינטרנט, צריך לבקש ממנהל המערכת להסיר את האפליקציות האלה.}many{כדי לוודא שאפשר להמשיך לגלוש באינטרנט, צריך לבקש ממנהל המערכת להסיר את האפליקציות האלה.}other{כדי לוודא שאפשר להמשיך לגלוש באינטרנט, צריך לבקש ממנהל המערכת להסיר את האפליקציות האלה.}}</translation>
 <translation id="5993332328670040093">השימוש בנתונים כבר לא יימדד.</translation>
 <translation id="600424552813877586">יישום לא חוקי.</translation>
 <translation id="6005695835120147974">נתב מדיה</translation>
@@ -3847,6 +3853,7 @@
 <translation id="7040138676081995583">פתח באמצעות...</translation>
 <translation id="7040230719604914234">ספק</translation>
 <translation id="7042418530779813870">הדבק וחפש</translation>
+<translation id="7043108582968290193">סיימת. לא נמצאו עוד אפליקציות שאינן תואמות.</translation>
 <translation id="7049293980323620022">להשאיר את הקובץ?</translation>
 <translation id="7051943809462976355">מחפש עכבר...</translation>
 <translation id="7052237160939977163">שלח נתוני מעקב אחר ביצועים</translation>
@@ -4017,6 +4024,7 @@
 <translation id="7328867076235380839">שילוב לא חוקי</translation>
 <translation id="7329154610228416156">הכניסה נכשלה מפני שהוגדר שימוש בכתובת אתר לא מאובטחת (<ph name="BLOCKED_URL" />). צור קשר עם מנהל המערכת.</translation>
 <translation id="7334190995941642545">‏מערכת Smart Lock אינה זמינה כרגע. נסה שוב מאוחר יותר.</translation>
+<translation id="7334274148831027933">הפעלת מגדיל במצב מעוגן</translation>
 <translation id="7339763383339757376">‏PKCS #7, אישור יחיד</translation>
 <translation id="7339785458027436441">בדוק איות בעת ההקלדה</translation>
 <translation id="7339898014177206373">חלון חדש</translation>
@@ -4381,6 +4389,7 @@
 <translation id="7912080627461681647">הסיסמה שלך שונתה בשרת. צא ולאחר מכן היכנס מחדש.</translation>
 <translation id="7912883689016444961">הגדרת רשת סלולרית</translation>
 <translation id="7915471803647590281">ספר לנו מה קורה לפני שליחת המשוב.</translation>
+<translation id="792514962475806987">רמת זום במצב מעוגן:</translation>
 <translation id="7925247922861151263">‏בדיקת AAA נכשלה</translation>
 <translation id="7925285046818567682">ממתין ל- <ph name="HOST_NAME" />...</translation>
 <translation id="7925686952655276919">אין להשתמש בנתונים ניידים עבור סנכרון</translation>
@@ -4762,6 +4771,7 @@
 <translation id="8546541260734613940">‎[*.]example.com</translation>
 <translation id="854655314928502177">‏כתובת האתר לגילוי אוטומטי של שרת proxy באינטרנט:</translation>
 <translation id="8546930481464505581">התאם אישית את סרגל המגע</translation>
+<translation id="8547013269961688403">הפעלת מגדיל במסך מלא</translation>
 <translation id="85486688517848470">החזק את מקש החיפוש כדי לשנות את ההתנהגות של מקשי השורה העליונה</translation>
 <translation id="855081842937141170">הצמד כרטיסייה</translation>
 <translation id="8551388862522347954">רישיונות</translation>
@@ -4816,6 +4826,7 @@
 <translation id="8642947597466641025">הגדל טקסט</translation>
 <translation id="8647834505253004544">כתובת האינטרנט לא חוקית</translation>
 <translation id="8648252583955599667"><ph name="GET_HELP_LINK" /> או <ph name="RE_SCAN_LINK" /></translation>
+<translation id="8650543407998814195">למרות שכבר אין לך גישה לפרופיל הישן, אפשר עדיין להסיר אותו.</translation>
 <translation id="8651585100578802546">אלץ טעינה מחדש של דף זה</translation>
 <translation id="8652400352452647993">שגיאת 'ארוז תוסף'</translation>
 <translation id="8652487083013326477">לחצן בחירה של טווח דפים</translation>
@@ -4892,7 +4903,9 @@
 <translation id="8737685506611670901">פתיחת קישורי <ph name="PROTOCOL" /> במקום <ph name="REPLACED_HANDLER_TITLE" /></translation>
 <translation id="8737709691285775803">Shill</translation>
 <translation id="8741316211671074806">תמונה בתוך תמונה</translation>
+<translation id="8743390665131937741">רמת זום במסך מלא:</translation>
 <translation id="8743864605301774756">עודכנה לפני שעה</translation>
+<translation id="874689135111202667">{0,plural, =1{להעלות קובץ אחד אל האתר הזה?}two{להעלות # קבצים אל האתר הזה?}many{להעלות # קבצים אל האתר הזה?}other{להעלות # קבצים אל האתר הזה?}}</translation>
 <translation id="8749863574775030885">‏גש למכשירי USB מספק לא ידוע</translation>
 <translation id="8754200782896249056">‏&lt;p&gt;בעת הפעלת <ph name="PRODUCT_NAME" /> בסביבה של שולחנות עבודה נתמכים, ייעשה שימוש בהגדרות ה-Proxy של המערכת. עם זאת, ייתכן שהמערכת שלך אינה נתמכת, או שאירעה בעיה בהפעלת תצורת המערכת.&lt;/p&gt;
 
@@ -5197,6 +5210,7 @@
 <translation id="960719561871045870">קוד ספק</translation>
 <translation id="960987915827980018">נותרה בערך שעה אחת</translation>
 <translation id="962802172452141067">עץ תיקיות של סימניות</translation>
+<translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{אפליקציה}two{אפליקציות}many{אפליקציות}other{אפליקציות}}</translation>
 <translation id="968000525894980488">‏מפעילים את שירותי Google Play.</translation>
 <translation id="968174221497644223">מטמון של יישום</translation>
 <translation id="969096075394517431">החלף שפות</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index 548205b..094b33e 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -968,7 +968,7 @@
 <translation id="2508428939232952663">Google Play स्टोअर खाते</translation>
 <translation id="2509495747794740764">स्केल मूल्य 10 आणि 200 दरम्यानचा नंबर असणे आवश्यक आहे.</translation>
 <translation id="2509566264613697683">८x</translation>
-<translation id="2512222046227390255">स्वयं-भरण फॉर्म</translation>
+<translation id="2512222046227390255">फॉर्म स्वयं-भरण करा</translation>
 <translation id="2515586267016047495">Alt</translation>
 <translation id="2517472476991765520">स्कॅन करा</translation>
 <translation id="2518024842978892609">आपली क्लायंट प्रमाणप‍त्रे वापरा</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index 9cad9cf7..2abfa91 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -972,7 +972,7 @@
 <translation id="2508428939232952663">Račun za Trgovino Google Play</translation>
 <translation id="2509495747794740764">Vrednost za prilagajanje velikosti mora biti število med 10 in 200.</translation>
 <translation id="2509566264613697683">8 x</translation>
-<translation id="2512222046227390255">Obrazci s samodejnim izpolnjevanjem</translation>
+<translation id="2512222046227390255">Samodejno izpolnjevanje obrazcev</translation>
 <translation id="2515586267016047495">Alt</translation>
 <translation id="2517472476991765520">Išči</translation>
 <translation id="2518024842978892609">Uporaba potrdil odjemalca</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 37da88b..9b8ff304 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -628,6 +628,7 @@
 <translation id="1944921356641260203">พบการอัปเดต</translation>
 <translation id="1951615167417147110">เลื่อนขึ้นหนึ่งหน้า</translation>
 <translation id="1956050014111002555">ไฟล์มีใบรับรองหลายใบ แต่ไม่มีการนำเข้าใบรับรอง:</translation>
+<translation id="1956390763342388273">การดำเนินการนี้จะอัปโหลดไฟล์ทั้งหมดจาก "<ph name="FOLDER_PATH" />" ดำเนินการนี้เฉพาะในกรณีที่คุณเชื่อถือเว็บไซต์ดังกล่าวเท่านั้น</translation>
 <translation id="1962233722219655970">หน้าเว็บนี้ใช้แอปพลิเคชัน Native Client ซึ่งไม่สามารถทำงานบนคอมพิวเตอร์ของคุณ</translation>
 <translation id="1962969542251276847">ล็อกหน้าจอ</translation>
 <translation id="1963227389609234879">นำออกทั้งหมด</translation>
@@ -840,6 +841,7 @@
 <translation id="2294358108254308676">คุณต้องการติดตั้ง <ph name="PRODUCT_NAME" /> หรือไม่</translation>
 <translation id="2296019197782308739">วิธีการ EAP:</translation>
 <translation id="2297705863329999812">ค้นหาเครื่องพิมพ์</translation>
+<translation id="2300383962156589922">ปรับแต่งและควบคุม <ph name="APP_NAME" /></translation>
 <translation id="2301382460326681002">ไดเรกทอรีหลักของส่วนขยายไม่ถูกต้อง</translation>
 <translation id="2302685579236571180">เข้าชมแบบไม่ระบุตัวตน</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" ขออนุญาตเพิ่มเติม</translation>
@@ -1328,6 +1330,7 @@
 <translation id="3012917896646559015">โปรดติดต่อผู้ผลิตฮาร์ดแวร์ของคุณทันที เพื่อส่งคอมพิวเตอร์ไปยังศูนย์ซ่อม</translation>
 <translation id="3013291976881901233">อุปกรณ์ MIDI</translation>
 <translation id="3014095112974898292">กำลังรอให้คำขออื่นๆ เสร็จสมบูรณ์...</translation>
+<translation id="3015639418649705390">เปิดใหม่เลย</translation>
 <translation id="3015992588037997514">รหัสนี้ปรากฏขึ้นบนหน้าจอ Chromebox ไหม</translation>
 <translation id="3016641847947582299">อัปเดตคอมโพเนนต์แล้ว</translation>
 <translation id="3016780570757425217">ทราบตำแหน่งของคุณ</translation>
@@ -2203,6 +2206,7 @@
 <translation id="4430369329743628066">เพิ่มบุ๊กมาร์กแล้ว</translation>
 <translation id="443454694385851356">แบบเดิม (ไม่ปลอดภัย)</translation>
 <translation id="443464694732789311">ต่อไป</translation>
+<translation id="443475966875174318">อัปเดตหรือนำแอปพลิเคชันที่ใช้ร่วมกันไม่ได้ออก</translation>
 <translation id="4439318412377770121">คุณต้องการลงทะเบียน <ph name="DEVICE_NAME" /> ไปยังอุปกรณ์ Google Cloud ใช่ไหม</translation>
 <translation id="4441124369922430666">คุณต้องการเริ่มแอปนี้โดยอัตโนมัติเมื่อเครื่องเปิดไหม</translation>
 <translation id="444134486829715816">ขยาย...</translation>
@@ -2385,6 +2389,7 @@
 <translation id="473775607612524610">การอัปเดต</translation>
 <translation id="474217410105706308">ปิดเสียงแท็บ</translation>
 <translation id="4742746985488890273">ตรึงที่ชั้นวาง</translation>
+<translation id="4743260470722568160"><ph name="BEGIN_LINK" />ดูวิธีอัปเดตแอปพลิเคชัน<ph name="END_LINK" /></translation>
 <translation id="4744574733485822359">การดาวน์โหลดของคุณเสร็จสิ้นแล้ว</translation>
 <translation id="4746971725921104503">ดูเหมือนว่าคุณกำลังจัดการผู้ใช้ที่มีชื่อนั้น คุณต้องการ<ph name="LINK_START" />นำเข้า <ph name="USER_DISPLAY_NAME" /> มายังอุปกรณ์นี้<ph name="LINK_END" />ไหม</translation>
 <translation id="4748762018725435655">จำเป็นต้องมีส่วนขยายจาก Chrome เว็บสโตร์</translation>
@@ -3195,6 +3200,7 @@
     <ph name="BEGIN_PARAGRAPH2" />คุณสามารถเปิดหรือปิดการตั้งค่านี้ได้ทุกเมื่อในการตั้งค่าแอป Android การตั้งค่านี้จะไม่ส่งผลต่อความสามารถในการส่งข้อมูลของอุปกรณ์เพื่อรับบริการที่จำเป็น เช่น การอัปเดตระบบและความปลอดภัย<ph name="END_PARAGRAPH2" /></translation>
 <translation id="5990386583461751448">แปลแล้ว</translation>
 <translation id="5991049340509704927">ขยาย</translation>
+<translation id="599131315899248751">{NUM_APPLICATIONS,plural, =1{โปรดขอให้ผู้ดูแลระบบนำแอปพลิเคชันนี้ออกเพื่อให้คุณท่องเว็บได้ต่อไป}other{โปรดขอให้ผู้ดูแลระบบนำแอปพลิเคชันนี้ออกเพื่อให้คุณท่องเว็บได้ต่อไป}}</translation>
 <translation id="5993332328670040093">ระบบจะไม่วัดการใช้อินเทอร์เน็ตของคุณอีกต่อไป</translation>
 <translation id="600424552813877586">แอปพลิเคชันไม่ถูกต้อง</translation>
 <translation id="6005695835120147974">เราเตอร์สื่อ</translation>
@@ -3850,6 +3856,7 @@
 <translation id="7040138676081995583">เปิดด้วย...</translation>
 <translation id="7040230719604914234">โอเปอเรเตอร์</translation>
 <translation id="7042418530779813870">&amp;วางและค้นหา</translation>
+<translation id="7043108582968290193">เรียบร้อย ไม่พบแอปพลิเคชันที่ใช้ร่วมกันไม่ได้</translation>
 <translation id="7049293980323620022">เก็บไฟล์ไว้ไหม</translation>
 <translation id="7051943809462976355">กำลังค้นหาเมาส์...</translation>
 <translation id="7052237160939977163">ส่งข้อมูลการติดตามผลการปฏิบัติงาน</translation>
@@ -4020,6 +4027,7 @@
 <translation id="7328867076235380839">ชุดค่าผสมไม่ถูกต้อง</translation>
 <translation id="7329154610228416156">การลงชื่อเข้าใช้ล้มเหลวเนื่องจากมีการกำหนดค่าให้ใช้ URL ที่ไม่ปลอดภัย (<ph name="BLOCKED_URL" />) โปรดติดต่อผู้ดูแลระบบของคุณ</translation>
 <translation id="7334190995941642545">ไม่สามารถใช้ Smart Lock ได้ในขณะนี้ โปรดลองอีกครั้งในภายหลัง</translation>
+<translation id="7334274148831027933">เปิดใช้แว่นขยายหน้าจอบางส่วน</translation>
 <translation id="7339763383339757376">PKCS #7, ใบรับรองแบบเดี่ยว</translation>
 <translation id="7339785458027436441">ตรวจสอบตัวสะกดขณะพิมพ์</translation>
 <translation id="7339898014177206373">หน้าต่างใหม่</translation>
@@ -4393,6 +4401,7 @@
 <translation id="7912080627461681647">มีการเปลี่ยนรหัสผ่านของคุณในเซิร์ฟเวอร์ โปรดออกจากระบบแล้วลงชื่อเข้าใช้อีกครั้ง</translation>
 <translation id="7912883689016444961">กำหนดค่าเครือข่ายมือถือ</translation>
 <translation id="7915471803647590281">โปรดแจ้งให้เราทราบถึงสิ่งที่เกิดขึ้นก่อนส่งความคิดเห็น</translation>
+<translation id="792514962475806987">ระดับการซูมหน้าจอบางส่วน:</translation>
 <translation id="7925247922861151263">การตรวจสอบ AAA ล้มเหลว</translation>
 <translation id="7925285046818567682">กำลังรอ <ph name="HOST_NAME" />...</translation>
 <translation id="7925686952655276919">อย่าใช้ข้อมูลมือถือสำหรับการซิงค์</translation>
@@ -4774,6 +4783,7 @@
 <translation id="8546541260734613940">[*.]example.com</translation>
 <translation id="854655314928502177">URL การค้นพบเว็บพร็อกซีโดยอัตโนมัติ:</translation>
 <translation id="8546930481464505581">ปรับแต่ง Touch Bar</translation>
+<translation id="8547013269961688403">เปิดใช้แว่นขยายทั้งหน้าจอ</translation>
 <translation id="85486688517848470">กดแป้น "ค้นหา" ค้างไว้เพื่อเปลี่ยนการทำงานของแป้นแถวบนสุด</translation>
 <translation id="855081842937141170">ตรึงแท็บ</translation>
 <translation id="8551388862522347954">ใบอนุญาต</translation>
@@ -4828,6 +4838,7 @@
 <translation id="8642947597466641025">ทำให้ข้อความใหญ่ขึ้น</translation>
 <translation id="8647834505253004544">ไม่ใช่ที่อยู่เว็บที่ถูกต้อง</translation>
 <translation id="8648252583955599667"><ph name="GET_HELP_LINK" /> หรือ <ph name="RE_SCAN_LINK" /></translation>
+<translation id="8650543407998814195">คุณยังคงนำโปรไฟล์เก่าออกได้ แม้จะเข้าถึงโปรไฟล์นั้นไม่ได้แล้วก็ตาม</translation>
 <translation id="8651585100578802546">ต้องโหลดหน้านี้ใหม่</translation>
 <translation id="8652400352452647993">ข้อผิดพลาดเกี่ยวกับการรวมแพ็กเกจส่วนขยาย</translation>
 <translation id="8652487083013326477">ปุ่มตัวเลือกช่วงหน้า</translation>
@@ -4904,7 +4915,9 @@
 <translation id="8737685506611670901">เปิดลิงก์ <ph name="PROTOCOL" /> แทน <ph name="REPLACED_HANDLER_TITLE" /></translation>
 <translation id="8737709691285775803">Shill</translation>
 <translation id="8741316211671074806">การแสดงภาพซ้อนภาพ</translation>
+<translation id="8743390665131937741">ระดับการซูมทั้งหน้าจอ:</translation>
 <translation id="8743864605301774756">อัปเดตเมื่อ 1 ชั่วโมงที่ผ่านมา</translation>
+<translation id="874689135111202667">{0,plural, =1{อัปโหลด 1 ไฟล์ไปยังเว็บไซต์นี้ใช่ไหม}other{อัปโหลด # ไฟล์ไปยังเว็บไซต์นี้ใช่ไหม}}</translation>
 <translation id="8749863574775030885">เข้าถึงอุปกรณ์ USB จากผู้ขายที่ไม่รู้จัก</translation>
 <translation id="8754200782896249056">&lt;p&gt;เมื่อเรียกใช้ <ph name="PRODUCT_NAME" /> ภายใต้สภาพแวดล้อมของเดสก์ท็อปที่สนับสนุน จะมีการใช้การตั้งค่าพร็อกซีของระบบ  อย่างไรก็ตาม ระบบของคุณอาจไม่ได้รับการสนับสนุนหรือมีปัญหาในการเปิดการกำหนดค่าระบบ&lt;/p&gt;
 
@@ -5209,6 +5222,7 @@
 <translation id="960719561871045870">รหัสผู้ให้บริการ</translation>
 <translation id="960987915827980018">เหลือเวลาอีกประมาณ 1 ชั่วโมง</translation>
 <translation id="962802172452141067">แผนผังของโฟลเดอร์บุ๊กมาร์ก</translation>
+<translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{แอปพลิเคชัน}other{แอปพลิเคชัน}}</translation>
 <translation id="968000525894980488">เปิดบริการ Google Play</translation>
 <translation id="968174221497644223">แคชของแอปพลิเคชัน</translation>
 <translation id="969096075394517431">เปลี่ยนภาษา</translation>
diff --git a/chrome/app/resources/google_chrome_strings_ru.xtb b/chrome/app/resources/google_chrome_strings_ru.xtb
index c7b519f..db7ba2ff 100644
--- a/chrome/app/resources/google_chrome_strings_ru.xtb
+++ b/chrome/app/resources/google_chrome_strings_ru.xtb
@@ -38,10 +38,12 @@
 <translation id="1873233029667955273">Google Chrome не является браузером по умолчанию.</translation>
 <translation id="1874309113135274312">Google Chrome (бета, mDNS-In)</translation>
 <translation id="1877026089748256423">Версия Chrome устарела</translation>
+<translation id="2007150628464581396">{0,plural, =1{Chrome перезапустится через 1 минуту}one{Chrome перезапустится через # минуту}few{Chrome перезапустится через # минуты}many{Chrome перезапустится через # минут}other{Chrome перезапустится через # минуты}}</translation>
 <translation id="2063848847527508675">Перезагрузите Chrome OS, чтобы установить обновление.</translation>
 <translation id="2077129598763517140">Использовать аппаратное ускорение (при наличии)</translation>
 <translation id="2084710999043359739">Установить</translation>
 <translation id="2094919256425865063">Завершить работу Chrome?</translation>
+<translation id="210890598424854131">{0,plural, =0{Chrome перезапускается}=1{Chrome перезапустится через 1 секунду}one{Chrome перезапустится через # секунду}few{Chrome перезапустится через # секунды}many{Chrome перезапустится через # секунд}other{Chrome перезапустится через # секунды}}</translation>
 <translation id="2120620239521071941">С устройства будут удалены объекты (<ph name="ITEMS_COUNT" />). Чтобы восстановить данные позже, войдите в Chrome как <ph name="USER_EMAIL" />.</translation>
 <translation id="2123055963409958220">Отправьте отчет о <ph name="BEGIN_LINK" />текущих настройках Chrome<ph name="END_LINK" />, чтобы помочь нам улучшить браузер</translation>
 <translation id="216054706567564023">Установите Chrome на телефон. Мы отправим SMS на номер, указанный в вашем аккаунте.</translation>
@@ -61,6 +63,7 @@
 <translation id="2446511512801740068">Для текущей версии Chrome доступно обновление. Оно будет установлено при перезапуске приложения.</translation>
 <translation id="2485422356828889247">Удалить</translation>
 <translation id="2534507159460261402">Google Pay (скопирована в Chrome)</translation>
+<translation id="2535429035253759792">Администратор просит перезапустить Chrome для установки обновления</translation>
 <translation id="2580411288591421699">Не удается установить версию Google Chrome, аналогичную уже выполняемой. Закройте Google Chrome и повторите попытку.</translation>
 <translation id="2586406160782125153">Данные о работе в браузере будут удалены с устройства. Чтобы восстановить данные позже, войдите в Chrome как <ph name="USER_EMAIL" />.</translation>
 <translation id="2588322182880276190">Логотип Chrome</translation>
@@ -97,6 +100,7 @@
 <translation id="345171907106878721">Добавить пользователя Chrome</translation>
 <translation id="3479552764303398839">Не сейчас</translation>
 <translation id="3503306920980160878">Для этого сайта Chrome запрашивает доступ к данным о вашем местоположении.</translation>
+<translation id="3582972582564653026">Синхронизируйте данные Chrome на всех устройствах</translation>
 <translation id="3612333635265770873">Известно, что модуль с таким названием конфликтует с Google Chrome.</translation>
 <translation id="3622797965165704966">Теперь с Chrome ещё удобнее работать в аккаунте Google, в том числе на общих компьютерах.</translation>
 <translation id="3637702109597584617"><ph name="TERMS_OF_SERVICE_LINK" />Условия использования<ph name="END_TERMS_OF_SERVICE_LINK" /> Google Chrome OS</translation>
@@ -119,6 +123,7 @@
 <translation id="4149882025268051530">Не удалось извлечь файлы из архива. Скачайте Google Chrome заново.</translation>
 <translation id="4251615635259297716">Связать данные Chrome с этим аккаунтом?</translation>
 <translation id="4251625577313994583">скачайте Chrome для iOS</translation>
+<translation id="4293420128516039005">Войдите, чтобы синхронизировать данные Chrome на всех устройствах</translation>
 <translation id="4309555186815777032">(необходимо <ph name="BEGIN_BUTTON" />перезапустить<ph name="END_BUTTON" /> Chrome)</translation>
 <translation id="4328355335528187361">Google Chrome для разработчиков (mDNS-In)</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
@@ -254,6 +259,7 @@
 <translation id="8547799825197623713">Панель запуска Chrome Canary</translation>
 <translation id="8556340503434111824">Доступна новая версия Google Chrome, которая стала еще быстрее.</translation>
 <translation id="8568392309447938879">Для работы с приложениями необходимо выполнить вход в Chrome. Это обеспечит синхронизацию приложений, закладок, истории, паролей и настроек, сохраненных на всех ваших устройствах.</translation>
+<translation id="859960207076826247">{0,plural, =0{Доступно обновление Chrome}=1{Доступно обновление Chrome}one{Обновление Chrome доступно # день}few{Обновление Chrome доступно # дня}many{Обновление Chrome доступно # дней}other{Обновление Chrome доступно # дня}}</translation>
 <translation id="8606668294522778825">Для более качественной работы Google Chrome может использовать веб-сервисы. При необходимости вы можете отключить их. <ph name="BEGIN_LINK" />Подробнее…<ph name="END_LINK" /></translation>
 <translation id="8614913330719544658">Google Chrome не отвечает. Перезапустить сейчас?</translation>
 <translation id="8667808506758191620">На устройстве <ph name="DEVICE_TYPE" /> используется последняя версия Chromium OS.</translation>
@@ -261,6 +267,7 @@
 <translation id="8679801911857917785">Кроме того, расширение изменило стартовую страницу Chrome.</translation>
 <translation id="870251953148363156">Обновить &amp;Google Chrome</translation>
 <translation id="873133009373065397">Google Chrome не удалось определить или задать браузер по умолчанию</translation>
+<translation id="8736674169840206667">Администратор требует перезапустить Chrome для установки обновления</translation>
 <translation id="8796108026289707191">Перезапустите Google Chrome</translation>
 <translation id="8823341990149967727">Версия Chrome устарела</translation>
 <translation id="884296878221830158">Кроме того, расширение изменило стартовую страницу Chrome и страницу, отображаемую при нажатии кнопки "Главная страница".</translation>
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index aaa3574..b6c997a8 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "chrome/browser/background_fetch/background_fetch_delegate_impl.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
@@ -357,9 +358,13 @@
   // Get visuals associated with the newly added offline item.
   std::unique_ptr<OfflineItemVisuals> out_visuals;
   GetVisualsForOfflineItemSync(offline_item.id, &out_visuals);
+#if defined(OS_ANDROID)
   EXPECT_FALSE(out_visuals->icon.IsEmpty());
   EXPECT_EQ(out_visuals->icon.Size().width(), 100);
   EXPECT_EQ(out_visuals->icon.Size().height(), 100);
+#else
+  EXPECT_TRUE(out_visuals->icon.IsEmpty());
+#endif
 }
 
 }  // namespace
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 7c00196..e58b071 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -10,6 +10,7 @@
 #include "base/guid.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -20,6 +21,7 @@
 #include "content/public/browser/background_fetch_response.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia.h"
 
 BackgroundFetchDelegateImpl::BackgroundFetchDelegateImpl(Profile* profile)
@@ -90,6 +92,22 @@
     offline_item.state = OfflineItemState::IN_PROGRESS;
 }
 
+void BackgroundFetchDelegateImpl::GetIconDisplaySize(
+    BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // If Android, return 192x192, else return 0x0. 0x0 means not loading an
+  // icon at all, which is returned for all non-Android platforms as the
+  // icons can't be displayed on the UI yet.
+  // TODO(nator): Move this logic to OfflineItemsCollection, and return icon
+  // size based on display.
+  gfx::Size display_size;
+#if defined(OS_ANDROID)
+  display_size = gfx::Size(192, 192);
+#endif
+  std::move(callback).Run(display_size);
+}
+
 void BackgroundFetchDelegateImpl::CreateDownloadJob(
     const std::string& job_unique_id,
     const std::string& title,
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 0581d444..66d0c81 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -48,6 +48,7 @@
   void Shutdown() override;
 
   // BackgroundFetchDelegate implementation:
+  void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
   void CreateDownloadJob(
       const std::string& job_unique_id,
       const std::string& title,
diff --git a/chrome/browser/browser_process_impl_unittest.cc b/chrome/browser/browser_process_impl_unittest.cc
index 84dccef..bd647ec 100644
--- a/chrome/browser/browser_process_impl_unittest.cc
+++ b/chrome/browser/browser_process_impl_unittest.cc
@@ -31,10 +31,9 @@
       : stashed_browser_process_(g_browser_process),
         loop_(base::MessageLoop::TYPE_UI),
         ui_thread_(content::BrowserThread::UI, &loop_),
-        io_thread_(new content::TestBrowserThread(content::BrowserThread::IO)),
         command_line_(base::CommandLine::NO_PROGRAM),
-        browser_process_impl_(std::make_unique<BrowserProcessImpl>(
-            base::ThreadTaskRunnerHandle::Get().get())) {
+        browser_process_impl_(
+            new BrowserProcessImpl(base::ThreadTaskRunnerHandle::Get().get())) {
     // Create() and StartWithDefaultParams() TaskScheduler in seperate steps to
     // properly simulate the browser process' lifecycle.
     base::TaskScheduler::Create("BrowserProcessImplTest");
@@ -49,17 +48,20 @@
     g_browser_process = stashed_browser_process_;
   }
 
-  // Creates the secondary thread (IO thread).
-  // The UI thread needs to be alive while BrowserProcessImpl is alive, and is
-  // managed separately.
+  // Creates the IO thread (unbound) and task scheduler threads. The UI thread
+  // needs to be alive while BrowserProcessImpl is alive, and is managed
+  // separately.
   void StartSecondaryThreads() {
     base::TaskScheduler::GetInstance()->StartWithDefaultParams();
-    io_thread_->StartIOThread();
+
+    io_thread_ = std::make_unique<content::TestBrowserThread>(
+        content::BrowserThread::IO);
+    io_thread_->StartIOThreadUnregistered();
   }
 
-  // Initializes the IO thread delegate and starts the ServiceManager.
+  // Binds the IO thread to BrowserThread::IO and starts the ServiceManager.
   void Initialize() {
-    io_thread_->InitIOThreadDelegate();
+    io_thread_->RegisterAsBrowserThread();
 
     // TestServiceManagerContext creation requires the task scheduler to be
     // started.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index 5845864..538e034 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -807,7 +807,9 @@
   for (size_t i = 0; i < params->urls.size(); ++i) {
     const FileSystemURL file_system_url =
         file_system_context->CrackURL(GURL(params->urls[i]));
-    DCHECK(external_backend->CanHandleType(file_system_url.type()));
+    DCHECK(external_backend->CanHandleType(file_system_url.type()))
+        << "GURL: " << file_system_url.ToGURL()
+        << "type: " << file_system_url.type();
     FileDefinition file_definition;
     const bool result =
         file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
diff --git a/chrome/browser/conflicts/problematic_programs_updater_win.cc b/chrome/browser/conflicts/problematic_programs_updater_win.cc
index ea345217..1d43888 100644
--- a/chrome/browser/conflicts/problematic_programs_updater_win.cc
+++ b/chrome/browser/conflicts/problematic_programs_updater_win.cc
@@ -279,24 +279,20 @@
 
   std::unique_ptr<chrome::conflicts::BlacklistAction> blacklist_action =
       module_list_filter_.IsBlacklisted(module_key, module_data);
-  if (blacklist_action) {
-    for (auto&& associated_program : associated_programs) {
-      problematic_programs_.emplace_back(std::move(associated_program),
-                                         std::move(blacklist_action));
-    }
-    return;
+  if (!blacklist_action) {
+    // The default behavior is to suggest to uninstall.
+    blacklist_action = std::make_unique<chrome::conflicts::BlacklistAction>();
+    blacklist_action->set_allow_load(true);
+    blacklist_action->set_message_type(
+        chrome::conflicts::BlacklistMessageType::UNINSTALL);
+    blacklist_action->set_message_url(std::string());
   }
 
-  // The default behavior is to suggest to uninstall.
-  blacklist_action = std::make_unique<chrome::conflicts::BlacklistAction>();
-  blacklist_action->set_allow_load(true);
-  blacklist_action->set_message_type(
-      chrome::conflicts::BlacklistMessageType::UNINSTALL);
-  blacklist_action->set_message_url(std::string());
-
   for (auto&& associated_program : associated_programs) {
-    problematic_programs_.emplace_back(std::move(associated_program),
-                                       std::move(blacklist_action));
+    problematic_programs_.emplace_back(
+        std::move(associated_program),
+        std::make_unique<chrome::conflicts::BlacklistAction>(
+            *blacklist_action));
   }
 }
 
diff --git a/chrome/browser/conflicts/problematic_programs_updater_win_unittest.cc b/chrome/browser/conflicts/problematic_programs_updater_win_unittest.cc
index 38977949..afdb372 100644
--- a/chrome/browser/conflicts/problematic_programs_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/problematic_programs_updater_win_unittest.cc
@@ -48,26 +48,24 @@
   ~MockInstalledPrograms() override = default;
 
   void AddInstalledProgram(const base::FilePath& file_path,
-                           InstalledPrograms::ProgramInfo program_info) {
+                           ProgramInfo program_info) {
     programs_.insert({file_path, std::move(program_info)});
   }
 
-  // Given a |file|, checks if it matches with an installed program on the
-  // user's machine and returns all the matching programs. Do not call this
-  // before the initialization is done.
-  // Virtual to allow mocking.
   bool GetInstalledPrograms(const base::FilePath& file,
                             std::vector<ProgramInfo>* programs) const override {
-    auto iter = programs_.find(file);
-    if (iter == programs_.end())
+    auto range = programs_.equal_range(file);
+
+    if (std::distance(range.first, range.second) == 0)
       return false;
 
-    programs->push_back(iter->second);
+    for (auto it = range.first; it != range.second; ++it)
+      programs->push_back(it->second);
     return true;
   }
 
  private:
-  std::map<base::FilePath, ProgramInfo> programs_;
+  std::multimap<base::FilePath, ProgramInfo> programs_;
 
   DISALLOW_COPY_AND_ASSIGN(MockInstalledPrograms);
 };
@@ -202,6 +200,24 @@
   EXPECT_EQ(L"Foo", program_names[0].info.name);
 }
 
+TEST_F(ProblematicProgramsUpdaterTest, SameModuleMultiplePrograms) {
+  AddProblematicProgram(dll1_, L"Foo", Option::ADD_REGISTRY_ENTRY);
+  AddProblematicProgram(dll1_, L"Bar", Option::ADD_REGISTRY_ENTRY);
+
+  auto problematic_programs_updater =
+      std::make_unique<ProblematicProgramsUpdater>(
+          exe_certificate_info(), module_list_filter(), installed_programs());
+
+  // Simulate the module loading into the process.
+  problematic_programs_updater->OnNewModuleFound(ModuleInfoKey(dll1_, 0, 0, 0),
+                                                 CreateLoadedModuleInfoData());
+  problematic_programs_updater->OnModuleDatabaseIdle();
+
+  EXPECT_TRUE(ProblematicProgramsUpdater::HasCachedPrograms());
+  auto program_names = ProblematicProgramsUpdater::GetCachedPrograms();
+  ASSERT_EQ(2u, program_names.size());
+}
+
 TEST_F(ProblematicProgramsUpdaterTest, MultipleCallsToOnModuleDatabaseIdle) {
   AddProblematicProgram(dll1_, L"Foo", Option::ADD_REGISTRY_ENTRY);
   AddProblematicProgram(dll2_, L"Bar", Option::ADD_REGISTRY_ENTRY);
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index 747efc8..a0250a4 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -142,7 +142,7 @@
       : public content::NavigationThrottle,
         public base::SupportsWeakPtr<WillStartRequestObserverThrottle> {
    public:
-    WillStartRequestObserverThrottle(content::NavigationHandle* handle)
+    explicit WillStartRequestObserverThrottle(content::NavigationHandle* handle)
         : NavigationThrottle(handle) {}
     ~WillStartRequestObserverThrottle() override {}
 
@@ -244,6 +244,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ServerRedirectSingleProcess) {
+  // TODO(lukasza): https://crbug.com/671734: Investigate why this test fails
+  // with --site-per-process.
+  if (content::AreAllSitesIsolatedForTesting())
+    return;
+
   ASSERT_TRUE(StartEmbeddedTestServer());
 
   // Set max renderers to 1 to force running out of processes.
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 6babbda..6a2d44b 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -223,7 +223,7 @@
           base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
                              head.mime_type.c_str()));
     }
-    client_->OnReceiveResponse(head, base::nullopt, nullptr);
+    client_->OnReceiveResponse(head, nullptr);
     client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
 
     uint32_t write_size = data->size();
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index 8c14def..f1f6963c 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -351,5 +352,26 @@
   return nullptr;
 }
 
+const Extension* GetPwaForSecureActiveTab(Browser* browser) {
+  switch (browser->toolbar_model()->GetSecurityLevel(true)) {
+    case security_state::SECURITY_LEVEL_COUNT:
+      NOTREACHED();
+      FALLTHROUGH;
+    case security_state::NONE:
+    case security_state::HTTP_SHOW_WARNING:
+    case security_state::DANGEROUS:
+      return nullptr;
+    case security_state::EV_SECURE:
+    case security_state::SECURE:
+    case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
+      break;
+  }
+  content::WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  return GetInstalledPwaForUrl(
+      web_contents->GetBrowserContext(),
+      web_contents->GetMainFrame()->GetLastCommittedURL());
+}
+
 }  // namespace util
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_util.h b/chrome/browser/extensions/extension_util.h
index ba9e713..8e56d09 100644
--- a/chrome/browser/extensions/extension_util.h
+++ b/chrome/browser/extensions/extension_util.h
@@ -23,6 +23,7 @@
 class ImageSkia;
 }
 
+class Browser;
 class GURL;
 class Profile;
 
@@ -120,6 +121,10 @@
     const GURL& url,
     base::Optional<LaunchContainer> launch_container_filter = base::nullopt);
 
+// Finds the first PWA with the active tab's url in its scope, returns nullptr
+// if there are none or the tab's is not secure.
+const Extension* GetPwaForSecureActiveTab(Browser* browser);
+
 }  // namespace util
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/native_bindings_apitest.cc b/chrome/browser/extensions/native_bindings_apitest.cc
index 0c59137..2a826f7 100644
--- a/chrome/browser/extensions/native_bindings_apitest.cc
+++ b/chrome/browser/extensions/native_bindings_apitest.cc
@@ -283,4 +283,13 @@
   EXPECT_FALSE(api_exists("chrome.browserAction"));
 }
 
+// Tests creating an API from a context that hasn't been initialized yet
+// by doing so in a parent frame. Regression test for https://crbug.com/819968.
+IN_PROC_BROWSER_TEST_F(NativeBindingsApiTest, APICreationFromNewContext) {
+  embedded_test_server()->ServeFilesFromDirectory(test_data_dir_);
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(RunExtensionTest("native_bindings/context_initialization"))
+      << message_;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc
index 55a9481..6e96b75 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -84,7 +84,7 @@
 }
 
 const base::Feature kUmaShortHWClass{"UmaShortHWClass",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
+                                     base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Called on a background thread to load hardware class information.
 std::string GetHardwareClassOnBackgroundThread() {
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index cc37548..4e10bde 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -242,6 +242,7 @@
       ASSERT_FALSE(filename.empty());
 
       std::string pdf_file = dir_name + "/" + filename;
+      SCOPED_TRACE(pdf_file);
       if (static_cast<int>(base::Hash(filename) % kNumberLoadTestParts) == k) {
         LOG(INFO) << "Loading: " << pdf_file;
         bool success = LoadPdf(embedded_test_server()->GetURL("/" + pdf_file));
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 8ead4fd..fc691c2 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -21,6 +21,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/prefs/pref_service.h"
+#include "components/printing/browser/features.h"
 #include "components/printing/browser/print_composite_client.h"
 #include "components/printing/browser/print_manager_utils.h"
 #include "components/printing/common/print_messages.h"
@@ -532,7 +533,9 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSitePerProcess)) {
+          switches::kSitePerProcess) ||
+      base::FeatureList::IsEnabled(
+          printing::features::kUsePdfCompositorServiceForPrint)) {
     EXPECT_TRUE(IsOopifEnabled());
   } else {
     EXPECT_FALSE(IsOopifEnabled());
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
index 223b559a..ecdd14d 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
@@ -39,7 +39,7 @@
     "RebootPromptDialog", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kUserInitiatedChromeCleanupsFeature{
-    "UserInitiatedChromeCleanups", base::FEATURE_DISABLED_BY_DEFAULT};
+    "UserInitiatedChromeCleanups", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kChromeCleanupDistributionFeature{
     "ChromeCleanupDistribution", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 290b903b..13a852b 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -4391,8 +4391,8 @@
   int ReadRawData(net::IOBuffer* buf, int buf_size) override {
     int bytes_read =
         std::min(static_cast<size_t>(buf_size),
-                 strlen(network_time::kGoodTimeResponseBody) - data_offset_);
-    memcpy(buf->data(), network_time::kGoodTimeResponseBody + data_offset_,
+                 strlen(network_time::kGoodTimeResponseBody[0]) - data_offset_);
+    memcpy(buf->data(), network_time::kGoodTimeResponseBody[0] + data_offset_,
            bytes_read);
     data_offset_ += bytes_read;
     return bytes_read;
@@ -4405,13 +4405,13 @@
         "Content-type: text/plain\n");
     headers.append(base::StringPrintf(
         "Content-Length: %1d\n",
-        static_cast<int>(strlen(network_time::kGoodTimeResponseBody))));
+        static_cast<int>(strlen(network_time::kGoodTimeResponseBody[0]))));
     info->headers =
         new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
             headers.c_str(), static_cast<int>(headers.length())));
     info->headers->AddHeader(
         "x-cup-server-proof: " +
-        std::string(network_time::kGoodTimeResponseServerProofHeader));
+        std::string(network_time::kGoodTimeResponseServerProofHeader[0]));
   }
 
   // Resumes a previously started request that was delayed. If no
@@ -4602,7 +4602,7 @@
   base::SimpleTestClock testing_clock;
   SSLErrorHandler::SetClockForTesting(&testing_clock);
   testing_clock.SetNow(
-      base::Time::FromJsTime(network_time::kGoodTimeResponseHandlerJsTime));
+      base::Time::FromJsTime(network_time::kGoodTimeResponseHandlerJsTime[0]));
   // Set the build time to match the testing clock, to ensure that the
   // build time heuristic doesn't fire.
   ssl_errors::SetBuildTimeForTesting(testing_clock.Now());
@@ -4650,7 +4650,7 @@
   base::SimpleTestClock testing_clock;
   SSLErrorHandler::SetClockForTesting(&testing_clock);
   testing_clock.SetNow(
-      base::Time::FromJsTime(network_time::kGoodTimeResponseHandlerJsTime));
+      base::Time::FromJsTime(network_time::kGoodTimeResponseHandlerJsTime[0]));
   testing_clock.Advance(base::TimeDelta::FromDays(30));
   // Set the build time to match the testing clock, to ensure that the
   // build time heuristic doesn't fire.
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index 1a2fd16..d6eb273 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -281,8 +281,8 @@
 
 void ProfileSyncServiceHarness::SignoutSyncService() {
   DCHECK(!username_.empty());
-  service()->GoogleSignedOut(service()->signin()->GetAuthenticatedAccountId(),
-                             username_);
+  service()->GoogleSignedOut(
+      service()->GetAuthenticatedAccountInfo().account_id, username_);
 }
 
 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index 5bf092fb..f4ecb6dc 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -428,7 +428,8 @@
   // want to block here and not create the HistogramTester below until we know
   // the cookie jar stats have been updated.
   UpdateCookieJarAccountsAndWait(
-      {GetClient(0)->service()->signin()->GetAuthenticatedAccountId()}, false);
+      {GetClient(0)->service()->GetAuthenticatedAccountInfo().account_id},
+      false);
 
   {
     HistogramTester histogram_tester;
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 6647784..a073dfb 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -931,6 +931,11 @@
 // http://www.google.com/chrome/intl/en/webmasters-faq.html#newtab will not
 // fork a new renderer process.
 IN_PROC_BROWSER_TEST_F(BrowserTest, OtherRedirectsDontForkProcess) {
+  // TODO(lukasza): https://crbug.com/824962: Investigate why this test fails
+  // with --site-per-process.
+  if (content::AreAllSitesIsolatedForTesting())
+    return;
+
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisablePopupBlocking);
 
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 66eb6a6..715dc6d 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/page_info/page_info_dialog.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -401,6 +402,10 @@
     case IDC_FULLSCREEN:
       chrome::ToggleFullscreenMode(browser_);
       break;
+    case IDC_OPEN_IN_PWA_WINDOW:
+      base::RecordAction(base::UserMetricsAction("OpenActiveTabInPwaWindow"));
+      ReparentSecureActiveTabIntoPwaWindow(browser_);
+      break;
 
 #if defined(OS_CHROMEOS)
     case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
@@ -833,6 +838,7 @@
   command_updater_.UpdateCommandEnabled(IDC_RESTORE_WINDOW, true);
   command_updater_.UpdateCommandEnabled(IDC_USE_SYSTEM_TITLE_BAR, true);
 #endif
+  command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_PWA_WINDOW, true);
 
   // Page-related commands
   command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true);
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 1eb9650f..42d50ab 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -434,8 +435,9 @@
   return feature && feature->IsAvailableToExtension(extension).is_available();
 }
 
-void ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
-                                       const extensions::Extension* extension) {
+Browser* ReparentWebContentsIntoAppBrowser(
+    content::WebContents* contents,
+    const extensions::Extension* extension) {
   Browser* source_browser = chrome::FindBrowserWithWebContents(contents);
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   // Incognito tabs reparent correctly, but remain incognito without any
@@ -454,4 +456,15 @@
           source_tabstrip->GetIndexOfWebContents(contents)),
       true);
   target_browser->window()->Show();
+
+  return target_browser;
+}
+
+Browser* ReparentSecureActiveTabIntoPwaWindow(Browser* browser) {
+  const extensions::Extension* extension =
+      extensions::util::GetPwaForSecureActiveTab(browser);
+  if (!extension)
+    return nullptr;
+  return ReparentWebContentsIntoAppBrowser(
+      browser->tab_strip_model()->GetActiveWebContents(), extension);
 }
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h
index bd1c96f..7d9770e 100644
--- a/chrome/browser/ui/extensions/application_launch.h
+++ b/chrome/browser/ui/extensions/application_launch.h
@@ -8,6 +8,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "url/gurl.h"
 
+class Browser;
 class Profile;
 
 namespace content {
@@ -37,7 +38,13 @@
 bool CanLaunchViaEvent(const extensions::Extension* extension);
 
 // Reparents |contents| into a new app browser for |extension|.
-void ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
-                                       const extensions::Extension* extension);
+Browser* ReparentWebContentsIntoAppBrowser(
+    content::WebContents* contents,
+    const extensions::Extension* extension);
+
+// Reparents the active tab into a new app browser for the PWA that has the
+// tab's URL in its scope. Does nothing if the tab is not secure or there is no
+// applicable PWA.
+Browser* ReparentSecureActiveTabIntoPwaWindow(Browser* browser);
 
 #endif  // CHROME_BROWSER_UI_EXTENSIONS_APPLICATION_LAUNCH_H_
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index e3eefc21..9b7fe1f 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/page_info/page_info_dialog.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -188,8 +189,15 @@
                                   "/ssl/page_displays_insecure_content.html");
   }
 
-  void InstallMixedContentPWA() {
-    GURL app_url = GetMixedContentAppURL();
+  GURL GetSecureAppURL() {
+    return https_server()->GetURL("app.com", "/ssl/google.html");
+  }
+
+  void InstallMixedContentPWA() { return InstallPWA(GetMixedContentAppURL()); }
+
+  void InstallSecurePWA() { return InstallPWA(GetSecureAppURL()); }
+
+  void InstallPWA(const GURL& app_url) {
     WebApplicationInfo web_app_info;
     web_app_info.app_url = app_url;
     web_app_info.scope = app_url.GetWithoutFilename();
@@ -249,6 +257,19 @@
     EXPECT_EQ(target_url, new_tab->GetLastCommittedURL());
   }
 
+  bool IsOpenInAppWindowOptionPresent(Browser* browser) {
+    DCHECK(!browser->hosted_app_controller())
+        << "This only applies to regular browser windows.";
+    auto model =
+        std::make_unique<AppMenuModel>(&empty_accelerator_provider_, browser);
+    model->Init();
+    for (int i = 0; i < model->GetItemCount(); ++i) {
+      if (model->GetCommandIdAt(i) == IDC_OPEN_IN_PWA_WINDOW)
+        return true;
+    }
+    return false;
+  }
+
   Browser* app_browser_;
   const extensions::Extension* app_;
 
@@ -257,6 +278,16 @@
   net::EmbeddedTestServer* https_server() { return &https_server_; }
 
  private:
+  class EmptyAcceleratorProvider : public ui::AcceleratorProvider {
+   public:
+    // Don't handle accelerators.
+    bool GetAcceleratorForCommandId(
+        int command_id,
+        ui::Accelerator* accelerator) const override {
+      return false;
+    }
+  } empty_accelerator_provider_;
+
   base::test::ScopedFeatureList scoped_feature_list_;
   AppType app_type_;
 
@@ -350,8 +381,8 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   CheckWebContentsDoesNotHaveAppPrefs(current_tab);
 
-  ReparentWebContentsIntoAppBrowser(current_tab, app_);
-  ASSERT_NE(browser(), chrome::FindLastActive());
+  Browser* app_browser = ReparentWebContentsIntoAppBrowser(current_tab, app_);
+  ASSERT_NE(browser(), app_browser);
 
   CheckWebContentsHasAppPrefs(
       chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents());
@@ -574,6 +605,27 @@
 
 using HostedAppPWAOnlyTest = HostedAppTest;
 
+// Tests that the command for OpenActiveTabInPwaWindow is available for secure
+// pages in an app's scope.
+IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest,
+                       ReparentSecureActiveTabIntoPwaWindow) {
+  ASSERT_TRUE(https_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  InstallSecurePWA();
+
+  NavigateToURLAndWait(browser(), GetSecureAppURL());
+  content::WebContents* tab_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_EQ(tab_contents->GetLastCommittedURL(), GetSecureAppURL());
+
+  EXPECT_TRUE(IsOpenInAppWindowOptionPresent(browser()));
+
+  Browser* app_browser = ReparentSecureActiveTabIntoPwaWindow(browser());
+
+  ASSERT_EQ(app_browser->hosted_app_controller()->GetExtension(), app_);
+}
+
 // Tests that mixed content is not loaded inside PWA windows.
 IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest, MixedContentInPWA) {
   ASSERT_TRUE(https_server()->Start());
@@ -603,6 +655,7 @@
 
   // The WebContents is just reparented, so mixed content is still not loaded.
   CheckMixedContentFailedToLoad(browser());
+  EXPECT_TRUE(IsOpenInAppWindowOptionPresent(browser()));
 
   ui_test_utils::UrlLoadObserver url_observer(
       GetMixedContentAppURL(), content::NotificationService::AllSources());
@@ -611,7 +664,10 @@
 
   // After reloading, mixed content should successfully load because the
   // WebContents is no longer in a PWA window.
+
   CheckMixedContentLoaded(browser());
+  EXPECT_FALSE(IsOpenInAppWindowOptionPresent(browser()));
+  EXPECT_EQ(ReparentSecureActiveTabIntoPwaWindow(browser()), nullptr);
 }
 
 // Tests that when calling ReparentWebContentsIntoAppBrowser, mixed content
@@ -630,10 +686,10 @@
 
   // A regular tab should be able to load mixed content.
   CheckMixedContentLoaded(browser());
+  EXPECT_FALSE(IsOpenInAppWindowOptionPresent(browser()));
 
-  ReparentWebContentsIntoAppBrowser(tab_contents, app_);
+  Browser* app_browser = ReparentWebContentsIntoAppBrowser(tab_contents, app_);
 
-  Browser* app_browser = chrome::FindLastActive();
   ASSERT_NE(app_browser, browser());
   ASSERT_EQ(GetMixedContentAppURL(), app_browser->tab_strip_model()
                                          ->GetActiveWebContents()
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index daf7ede..c330bc8 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -466,6 +466,50 @@
 
 #endif  // !defined(OS_CHROMEOS)
 
+#if defined(OS_WIN)
+IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, ValidNotificationLaunchId) {
+  // This test execises NotificationPlatformBridgeWin, which is not enabled in
+  // older versions of Windows.
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  // Simulate a launch from the notification_helper process which appends the
+  // kNotificationLaunchId switch to the command line.
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchNative(
+      switches::kNotificationLaunchId,
+      L"1|1|0|Default|0|https://example.com/|notification_id");
+  chrome::startup::IsFirstRun first_run =
+      first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN
+                                    : chrome::startup::IS_NOT_FIRST_RUN;
+  StartupBrowserCreatorImpl launch(base::FilePath(), command_line, first_run);
+  ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
+
+  // The launch delegates to the notification system and doesn't open any new
+  // browser window.
+  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
+}
+
+IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, InvalidNotificationLaunchId) {
+  // This test execises NotificationPlatformBridgeWin, which is not enabled in
+  // older versions of Windows.
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  // Simulate a launch with invalid launch id, which will fail.
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchNative(switches::kNotificationLaunchId, L"");
+  chrome::startup::IsFirstRun first_run =
+      first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN
+                                    : chrome::startup::IS_NOT_FIRST_RUN;
+  StartupBrowserCreatorImpl launch(base::FilePath(), command_line, first_run);
+  ASSERT_FALSE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
+
+  // No new browser window is open.
+  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
+}
+#endif  // defined(OS_WIN)
+
 IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest,
                        ReadingWasRestartedAfterRestart) {
   // Tests that StartupBrowserCreator::WasRestarted reads and resets the
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 1da3c0e..d1eb77c 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -69,6 +69,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/text_elider.h"
 
 #if defined(GOOGLE_CHROME_BUILD)
 #include "base/feature_list.h"
@@ -91,6 +92,8 @@
 
 namespace {
 
+constexpr size_t kMaxAppNameLength = 30;
+
 #if defined(OS_MACOSX)
 // An empty command used because of a bug in AppKit menus.
 // See comment in CreateActionToolbarOverflowMenu().
@@ -768,7 +771,18 @@
   AddItemWithStringId(IDC_FIND, IDS_FIND);
   if (extensions::util::IsNewBookmarkAppsEnabled() &&
       banners::AppBannerManager::IsExperimentalAppBannersEnabled()) {
-    AddItem(IDC_CREATE_HOSTED_APP, GetCreateHostedAppMenuItemName(browser_));
+    const extensions::Extension* pwa =
+        extensions::util::GetPwaForSecureActiveTab(browser_);
+    if (pwa) {
+      AddItem(
+          IDC_OPEN_IN_PWA_WINDOW,
+          l10n_util::GetStringFUTF16(
+              IDS_OPEN_IN_APP_WINDOW,
+              gfx::TruncateString(base::UTF8ToUTF16(pwa->name()),
+                                  kMaxAppNameLength, gfx::CHARACTER_BREAK)));
+    } else {
+      AddItem(IDC_CREATE_HOSTED_APP, GetCreateHostedAppMenuItemName(browser_));
+    }
   }
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/ui/views/frame/browser_native_widget_window_mac.mm b/chrome/browser/ui/views/frame/browser_native_widget_window_mac.mm
index 17bdc8ae..1928e75 100644
--- a/chrome/browser/ui/views/frame/browser_native_widget_window_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_native_widget_window_mac.mm
@@ -57,9 +57,9 @@
 // NSWindow (PrivateAPI) overrides.
 
 + (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
-  // - Ignore fullscreen so that the drop-down title bar isn't huge.
   // - NSThemeFrame and its subclasses will be nil if it's missing at runtime.
-  if (!(windowStyle & NSFullScreenWindowMask) && [BrowserWindowFrame class])
+  if ([BrowserWindowFrame class])
+    // TODO(crbug/825968): fullscreen should have a reduced titlebar height.
     return [BrowserWindowFrame class];
   return [super frameViewClassForStyleMask:windowStyle];
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
index 81f127ee..5da4371 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
@@ -257,7 +257,8 @@
         net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
     network::ResourceResponseHead resource_response;
     resource_response.mime_type = "text/html";
-    params->client->OnReceiveResponse(resource_response, ssl_info,
+    resource_response.ssl_info = ssl_info;
+    params->client->OnReceiveResponse(resource_response,
                                       /*downloaded_file=*/nullptr);
     network::URLLoaderCompletionStatus completion_status;
     completion_status.ssl_info = ssl_info;
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc
index ddd08d1..7175c33 100644
--- a/chrome/browser/ui/views/session_crashed_bubble_view.cc
+++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc
@@ -50,6 +50,7 @@
 #if defined(OS_MACOSX)
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
+#include "chrome/browser/ui/cocoa/bubble_anchor_helper_views.h"
 #endif
 
 using views::GridLayout;
@@ -189,6 +190,10 @@
       GetBubbleAnchorView(browser), GetBubbleAnchorRect(browser), browser,
       offer_uma_optin);
   views::BubbleDialogDelegateView::CreateBubble(crash_bubble)->Show();
+#if defined(OS_MACOSX)
+  if (views_mode_controller::IsViewsBrowserCocoa())
+    KeepBubbleAnchored(crash_bubble);
+#endif
 
   RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_SHOWN);
   if (uma_opted_in_already)
diff --git a/chrome/browser/vr/OWNERS b/chrome/browser/vr/OWNERS
index 0da39c09..ac28062 100644
--- a/chrome/browser/vr/OWNERS
+++ b/chrome/browser/vr/OWNERS
@@ -10,4 +10,7 @@
 # WebVR-related
 klausw@chromium.org
 
+# Browser Test-related
+bsheedy@chromium.org
+
 # COMPONENT: UI>Browser>VR
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
index b6b6581..c470940 100644
--- a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
@@ -65,7 +65,11 @@
 function gotStream(stream) {
   console.log('Received local stream', stream);
   var video = document.querySelector('video');
-  video.src = URL.createObjectURL(stream);
+  try {
+    video.srcObject = stream;
+  } catch (error) {
+    video.src = URL.createObjectURL(stream);
+  }
   stream.onended = function() { console.log('Ended'); };
 
   pc1 = new RTCPeerConnection();
@@ -107,7 +111,11 @@
 function gotRemoteStream(event) {
   // Call the polyfill wrapper to attach the media stream to this element.
   console.log('hitting this code');
-  remoteVideo.src = URL.createObjectURL(event.stream);
+  try {
+    remoteVideo.srcObject = event.stream;
+  } catch (error) {
+    remoteVideo.src = URL.createObjectURL(event.stream);
+  }
 }
 
 function onCreateAnswerSuccess(desc) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fc9e318..e438975 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4478,10 +4478,6 @@
       ]
       configs += [ "//build/config:precompiled_headers" ]
 
-      data_deps = [
-        "//testing/buildbot/filters:interactive_ui_tests_filters",
-      ]
-
       defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
       ldflags = []
 
@@ -4614,10 +4610,6 @@
 
     configs += [ "//build/config:precompiled_headers" ]
 
-    data_deps = [
-      "//testing/buildbot/filters:interactive_ui_tests_filters",
-    ]
-
     data = [
       "data/",
       "//chrome/third_party/mock4js/",
@@ -4703,7 +4695,7 @@
     }
 
     # Runtime dependencies
-    data_deps += [
+    data_deps = [
       "//ppapi:ppapi_tests",
       "//third_party/mesa:osmesa",
     ]
diff --git a/chrome/test/data/extensions/api_test/native_bindings/context_initialization/background.js b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/background.js
new file mode 100644
index 0000000..bcc628a
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/background.js
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let i = document.createElement('iframe');
+i.src = chrome.runtime.getURL('iframe.html');
+document.body.appendChild(i);
+// Before the child frame has a chance to load (and thus before the
+// ScriptContext is initialized), execute code in the child frame that
+// initializes an API in the main frame (this frame). The contextMenus API
+// requires JS initialization, which requires a JSRunner be instantiated for
+// the context. If the new context (which is uninitialized and has no JSRunner)
+// is used, this will fail. Instead, it should execute in this frame's context.
+// See https://crbug.com/819968 for more details.
+// IMPORTANT: For this test to be valid, the API being initialized (here,
+// contextMenus), must have custom JS bindings.
+i.contentWindow.eval('parent.chrome.contextMenus;');
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/native_bindings/context_initialization/iframe.html b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/iframe.html
new file mode 100644
index 0000000..825c61e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/iframe.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<html>
+</html>
diff --git a/chrome/test/data/extensions/api_test/native_bindings/context_initialization/manifest.json b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/manifest.json
new file mode 100644
index 0000000..9113ecc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/native_bindings/context_initialization/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Extension test",
+  "manifest_version": 2,
+  "background": {"scripts": ["background.js"]},
+  "version": "0.1",
+  "permissions": ["storage", "contextMenus"],
+  // Note: we have to allow unsafe-eval here for the test.
+  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';"
+}
diff --git a/chromecast/base/bind_to_task_runner.h b/chromecast/base/bind_to_task_runner.h
index 314bd95f..4daebb9 100644
--- a/chromecast/base/bind_to_task_runner.h
+++ b/chromecast/base/bind_to_task_runner.h
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_task_runner_handle.h"
 
 // This is a helper utility for Bind()ing callbacks to a given TaskRunner.
@@ -82,6 +83,19 @@
                           std::move(callback));
 }
 
+template <typename T>
+base::OnceCallback<T> BindToCurrentSequence(base::OnceCallback<T> callback) {
+  return BindToTaskRunner(base::SequencedTaskRunnerHandle::Get(),
+                          std::move(callback));
+}
+
+template <typename T>
+base::RepeatingCallback<T> BindToCurrentSequence(
+    base::RepeatingCallback<T> callback) {
+  return BindToTaskRunner(base::SequencedTaskRunnerHandle::Get(),
+                          std::move(callback));
+}
+
 }  // namespace chromecast
 
 #endif  // CHROMECAST_BASE_BIND_TO_TASK_RUNNER_H_
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java
index 1989050..5f6640f 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java
@@ -102,7 +102,7 @@
         mContentViewCore = ContentViewCore.create(this, "", webContents,
                 ViewAndroidDelegate.createBasicDelegate(mContentView), mContentView, mWindow);
         // Enable display of current webContents.
-        mContentViewCore.onShow();
+        webContents.onShow();
     }
 
     // Remove the currently displayed webContents. no-op if nothing is being displayed.
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsSurfaceHelper.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsSurfaceHelper.java
index 32235c4..53970b4 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsSurfaceHelper.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsSurfaceHelper.java
@@ -210,13 +210,13 @@
         mContentViewCore = ContentViewCore.create(context, "", webContents,
                 ViewAndroidDelegate.createBasicDelegate(mContentView), mContentView, mWindow);
         // Enable display of current webContents.
-        mContentViewCore.onShow();
+        webContents.onShow();
         mCastWebContentsLayout.addView(mContentView,
                 new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                         FrameLayout.LayoutParams.MATCH_PARENT));
         mContentView.setFocusable(true);
         mContentView.requestFocus();
-        mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
+        mContentViewRenderView.setCurrentWebContents(webContents);
     }
 
     // Remove the currently displayed webContents. no-op if nothing is being displayed.
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager.cc b/chromecast/device/bluetooth/le/gatt_client_manager.cc
index a1a06ba..d6c6710 100644
--- a/chromecast/device/bluetooth/le/gatt_client_manager.cc
+++ b/chromecast/device/bluetooth/le/gatt_client_manager.cc
@@ -75,7 +75,7 @@
 void GattClientManager::GetDevice(
     const bluetooth_v2_shlib::Addr& addr,
     base::OnceCallback<void(scoped_refptr<RemoteDevice>)> cb) {
-  MAKE_SURE_IO_THREAD(GetDevice, addr, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(GetDevice, addr, BindToCurrentSequence(std::move(cb)));
   DCHECK(cb);
   std::move(cb).Run(GetDeviceSync(addr));
 }
diff --git a/chromecast/device/bluetooth/le/le_scan_manager.cc b/chromecast/device/bluetooth/le/le_scan_manager.cc
index 92e1457..fbb3bde9 100644
--- a/chromecast/device/bluetooth/le/le_scan_manager.cc
+++ b/chromecast/device/bluetooth/le/le_scan_manager.cc
@@ -109,7 +109,7 @@
 
 void LeScanManager::SetScanEnable(bool enable, SetScanEnableCallback cb) {
   MAKE_SURE_IO_THREAD(SetScanEnable, enable,
-                      BindToCurrentThread(std::move(cb)));
+                      BindToCurrentSequence(std::move(cb)));
   bool success;
   if (enable) {
     success = le_scanner_->StartScan();
@@ -129,7 +129,7 @@
 
 void LeScanManager::GetScanResults(GetScanResultsCallback cb,
                                    base::Optional<uint16_t> service_uuid) {
-  MAKE_SURE_IO_THREAD(GetScanResults, BindToCurrentThread(std::move(cb)),
+  MAKE_SURE_IO_THREAD(GetScanResults, BindToCurrentSequence(std::move(cb)),
                       service_uuid);
   std::move(cb).Run(GetScanResultsInternal(service_uuid));
 }
diff --git a/chromecast/device/bluetooth/le/remote_characteristic.cc b/chromecast/device/bluetooth/le/remote_characteristic.cc
index f416def..7a9ecf1 100644
--- a/chromecast/device/bluetooth/le/remote_characteristic.cc
+++ b/chromecast/device/bluetooth/le/remote_characteristic.cc
@@ -105,7 +105,7 @@
 void RemoteCharacteristic::SetRegisterNotification(bool enable,
                                                    StatusCallback cb) {
   MAKE_SURE_IO_THREAD(SetRegisterNotification, enable,
-                      BindToCurrentThread(std::move(cb)));
+                      BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false);
@@ -129,7 +129,7 @@
 
 void RemoteCharacteristic::SetNotification(bool enable, StatusCallback cb) {
   MAKE_SURE_IO_THREAD(SetNotification, enable,
-                      BindToCurrentThread(std::move(cb)));
+                      BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false);
@@ -148,7 +148,7 @@
     bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
     ReadCallback callback) {
   MAKE_SURE_IO_THREAD(ReadAuth, auth_req,
-                      BindToCurrentThread(std::move(callback)));
+                      BindToCurrentSequence(std::move(callback)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(callback, false, {});
@@ -177,7 +177,7 @@
     const std::vector<uint8_t>& value,
     StatusCallback callback) {
   MAKE_SURE_IO_THREAD(WriteAuth, auth_req, write_type, value,
-                      BindToCurrentThread(std::move(callback)));
+                      BindToCurrentSequence(std::move(callback)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(callback, false);
diff --git a/chromecast/device/bluetooth/le/remote_descriptor.cc b/chromecast/device/bluetooth/le/remote_descriptor.cc
index 0f9da2b..727e17f 100644
--- a/chromecast/device/bluetooth/le/remote_descriptor.cc
+++ b/chromecast/device/bluetooth/le/remote_descriptor.cc
@@ -61,7 +61,7 @@
     bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
     ReadCallback callback) {
   MAKE_SURE_IO_THREAD(ReadAuth, auth_req,
-                      BindToCurrentThread(std::move(callback)));
+                      BindToCurrentSequence(std::move(callback)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(callback, false, {});
@@ -90,7 +90,7 @@
     const std::vector<uint8_t>& value,
     StatusCallback callback) {
   MAKE_SURE_IO_THREAD(WriteAuth, auth_req, value,
-                      BindToCurrentThread(std::move(callback)));
+                      BindToCurrentSequence(std::move(callback)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(callback, false);
diff --git a/chromecast/device/bluetooth/le/remote_device.cc b/chromecast/device/bluetooth/le/remote_device.cc
index 8f8684d..03a9eba 100644
--- a/chromecast/device/bluetooth/le/remote_device.cc
+++ b/chromecast/device/bluetooth/le/remote_device.cc
@@ -66,7 +66,7 @@
 RemoteDevice::~RemoteDevice() = default;
 
 void RemoteDevice::Connect(StatusCallback cb) {
-  MAKE_SURE_IO_THREAD(Connect, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(Connect, BindToCurrentSequence(std::move(cb)));
   if (!ConnectSync()) {
     // Error logged.
     EXEC_CB_AND_RET(cb, false);
@@ -96,7 +96,7 @@
 }
 
 void RemoteDevice::Disconnect(StatusCallback cb) {
-  MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentSequence(std::move(cb)));
   if (!DisconnectSync()) {
     // Error logged.
     EXEC_CB_AND_RET(cb, false);
@@ -127,7 +127,7 @@
 }
 
 void RemoteDevice::ReadRemoteRssi(RssiCallback cb) {
-  MAKE_SURE_IO_THREAD(ReadRemoteRssi, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(ReadRemoteRssi, BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false, 0);
@@ -146,7 +146,7 @@
 }
 
 void RemoteDevice::RequestMtu(int mtu, StatusCallback cb) {
-  MAKE_SURE_IO_THREAD(RequestMtu, mtu, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(RequestMtu, mtu, BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false);
@@ -172,7 +172,7 @@
                                              int timeout,
                                              StatusCallback cb) {
   MAKE_SURE_IO_THREAD(ConnectionParameterUpdate, min_interval, max_interval,
-                      latency, timeout, BindToCurrentThread(std::move(cb)));
+                      latency, timeout, BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false);
@@ -184,7 +184,7 @@
 }
 
 void RemoteDevice::DiscoverServices(DiscoverServicesCb cb) {
-  MAKE_SURE_IO_THREAD(DiscoverServices, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(DiscoverServices, BindToCurrentSequence(std::move(cb)));
   if (!gatt_client_manager_) {
     LOG(ERROR) << __func__ << " failed: Destroyed";
     EXEC_CB_AND_RET(cb, false, {});
@@ -219,7 +219,7 @@
 
 void RemoteDevice::GetServices(
     base::OnceCallback<void(std::vector<scoped_refptr<RemoteService>>)> cb) {
-  MAKE_SURE_IO_THREAD(GetServices, BindToCurrentThread(std::move(cb)));
+  MAKE_SURE_IO_THREAD(GetServices, BindToCurrentSequence(std::move(cb)));
   auto ret = GetServicesSync();
   EXEC_CB_AND_RET(cb, std::move(ret));
 }
@@ -238,7 +238,7 @@
     const bluetooth_v2_shlib::Uuid& uuid,
     base::OnceCallback<void(scoped_refptr<RemoteService>)> cb) {
   MAKE_SURE_IO_THREAD(GetServiceByUuid, uuid,
-                      BindToCurrentThread(std::move(cb)));
+                      BindToCurrentSequence(std::move(cb)));
   auto ret = GetServiceByUuidSync(uuid);
   EXEC_CB_AND_RET(cb, std::move(ret));
 }
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
index d576d7b7..63bbf37 100644
--- a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
+++ b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
@@ -125,8 +125,9 @@
         context_getter_(
             new net::TestURLRequestContextGetter(network_task_runner)) {
     network_task_runner->PostTask(
-        FROM_HERE, base::Bind(&TestDelegate::CreateProxyServiceOnNetworkThread,
-                              base::Unretained(this)));
+        FROM_HERE,
+        base::Bind(&TestDelegate::CreateProxyResolutionServiceOnNetworkThread,
+                   base::Unretained(this)));
     RunPendingTasks(network_task_runner);
   }
 
@@ -145,7 +146,7 @@
  private:
   // Helper method for the constructor that initializes
   // |proxy_resolution_service_| and injects it into |context_getter_|'s context.
-  void CreateProxyServiceOnNetworkThread() {
+  void CreateProxyResolutionServiceOnNetworkThread() {
     CHECK(context_getter_->GetNetworkTaskRunner()->BelongsToCurrentThread());
 
     // Setting a mandatory PAC URL makes |proxy_resolution_service_| query
diff --git a/components/apdu/apdu_command.cc b/components/apdu/apdu_command.cc
index d5e9967..a4d9d8a 100644
--- a/components/apdu/apdu_command.cc
+++ b/components/apdu/apdu_command.cc
@@ -119,8 +119,12 @@
   }
 
   if (response_length_ > 0) {
-    encoded.push_back((response_length_ >> 8) & 0xff);
-    encoded.push_back(response_length_ & 0xff);
+    size_t response_length = response_length_;
+    if (response_length > kApduMaxResponseLength)
+      response_length = kApduMaxResponseLength;
+    // A zero value represents a response length of 65,536 bytes.
+    encoded.push_back((response_length >> 8) & 0xff);
+    encoded.push_back(response_length & 0xff);
   }
   return encoded;
 }
diff --git a/components/apdu/apdu_command.h b/components/apdu/apdu_command.h
index 07f16ba8..a43a7c5 100644
--- a/components/apdu/apdu_command.h
+++ b/components/apdu/apdu_command.h
@@ -61,6 +61,8 @@
   size_t response_length() const { return response_length_; }
   const std::vector<uint8_t>& data() const { return data_; }
 
+  static constexpr size_t kApduMaxResponseLength = 65536;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ApduTest, TestDeserializeBasic);
   FRIEND_TEST_ALL_PREFIXES(ApduTest, TestDeserializeComplex);
@@ -76,7 +78,6 @@
   // also limited to 16 bits in length with a value of 0x0000 corresponding to
   // a length of 65536.
   static constexpr size_t kApduMaxDataLength = 65535;
-  static constexpr size_t kApduMaxResponseLength = 65536;
   static constexpr size_t kApduMaxLength =
       kApduMaxDataLength + kApduMaxHeader + 2;
 
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index f9d8ed44..ad18985 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -968,7 +968,6 @@
 
 void AutofillAgent::ResetLastInteractedElements() {
   last_interacted_form_.Reset();
-  last_clicked_form_control_element_for_testing_.Reset();
   formless_elements_user_edited_.clear();
   provisionally_saved_form_.reset();
 }
diff --git a/components/autofill/content/renderer/form_tracker.cc b/components/autofill/content/renderer/form_tracker.cc
index 75cbae1..6f76a87 100644
--- a/components/autofill/content/renderer/form_tracker.cc
+++ b/components/autofill/content/renderer/form_tracker.cc
@@ -143,10 +143,8 @@
 void FormTracker::DidCommitProvisionalLoad(bool is_new_navigation,
                                            bool is_same_document_navigation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
-  if (!is_same_document_navigation) {
-    ResetLastInteractedElements();
+  if (!is_same_document_navigation)
     return;
-  }
 
   FireSubmissionIfFormDisappear(SubmissionSource::SAME_DOCUMENT_NAVIGATION);
 }
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 0d06dfc..4215f63 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -181,14 +181,6 @@
   binding_.Bind(std::move(request));
 }
 
-void PasswordGenerationAgent::DidCommitProvisionalLoad(
-    bool /*is_new_navigation*/, bool is_same_document_navigation) {
-  if (is_same_document_navigation)
-    return;
-  generation_element_.Reset();
-  last_focused_password_element_.Reset();
-}
-
 void PasswordGenerationAgent::DidFinishDocumentLoad() {
   // Update stats for main frame navigation.
   if (!render_frame()->GetWebFrame()->Parent()) {
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index f23cf5ac..adebf24 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -94,8 +94,6 @@
   typedef std::vector<AccountCreationFormData> AccountCreationFormDataList;
 
   // RenderFrameObserver:
-  void DidCommitProvisionalLoad(bool is_new_navigation,
-                                bool is_same_document_navigation) override;
   void DidFinishDocumentLoad() override;
   void DidFinishLoad() override;
   void OnDestruct() override;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index db105fc..d5d4d9e 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -336,14 +336,14 @@
 void ProfileSyncService::RegisterAuthNotifications() {
   DCHECK(thread_checker_.CalledOnValidThread());
   oauth2_token_service_->AddObserver(this);
-  if (signin())
-    signin()->AddObserver(this);
+  if (signin_)
+    signin_->GetOriginal()->AddObserver(this);
 }
 
 void ProfileSyncService::UnregisterAuthNotifications() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (signin())
-    signin()->RemoveObserver(this);
+  if (signin_)
+    signin_->GetOriginal()->RemoveObserver(this);
   if (oauth2_token_service_)
     oauth2_token_service_->RemoveObserver(this);
 }
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc
index 9dd89b08..ae116462 100644
--- a/components/cronet/android/cronet_library_loader.cc
+++ b/components/cronet/android/cronet_library_loader.cc
@@ -155,8 +155,8 @@
   return service;
 }
 
-// Creates a proxy service appropriate for this platform.
-std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+// Creates a proxy resolution service appropriate for this platform.
+std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     net::NetLog* net_log) {
   // Android provides a local HTTP proxy server that handles proxying when a PAC
diff --git a/components/cronet/cronet_global_state.h b/components/cronet/cronet_global_state.h
index c5318f6..4a3a2b23 100644
--- a/components/cronet/cronet_global_state.h
+++ b/components/cronet/cronet_global_state.h
@@ -39,10 +39,10 @@
 std::unique_ptr<net::ProxyConfigService> CreateProxyConfigService(
     const scoped_refptr<base::SequencedTaskRunner>& io_task_runner);
 
-// Creates a proxy service appropriate for this platform that fetches the
-// system proxy settings. Cronet will call this API only after a prior call
+// Creates a proxy resolution service appropriate for this platform that fetches
+// the system proxy settings. Cronet will call this API only after a prior call
 // to EnsureInitialized() has returned.
-std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     net::NetLog* net_log);
 
diff --git a/components/cronet/cronet_global_state_stubs.cc b/components/cronet/cronet_global_state_stubs.cc
index 7980e77..4ebc304 100644
--- a/components/cronet/cronet_global_state_stubs.cc
+++ b/components/cronet/cronet_global_state_stubs.cc
@@ -62,7 +62,7 @@
   return nullptr;
 }
 
-std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     net::NetLog* net_log) {
   // TODO(https://crbug.com/813226): Add ProxyResolutionService support.
diff --git a/components/cronet/cronet_url_request_context.cc b/components/cronet/cronet_url_request_context.cc
index 746116b6..507efbb 100644
--- a/components/cronet/cronet_url_request_context.cc
+++ b/components/cronet/cronet_url_request_context.cc
@@ -319,8 +319,9 @@
       std::make_unique<BasicNetworkDelegate>());
   context_builder.set_net_log(g_net_log.Get().net_log());
 
-  context_builder.set_proxy_resolution_service(cronet::CreateProxyService(
-      std::move(proxy_config_service), g_net_log.Get().net_log()));
+  context_builder.set_proxy_resolution_service(
+      cronet::CreateProxyResolutionService(std::move(proxy_config_service),
+                                           g_net_log.Get().net_log()));
 
   config->ConfigureURLRequestContextBuilder(&context_builder,
                                             g_net_log.Get().net_log());
diff --git a/components/cronet/ios/cronet_global_state_ios.mm b/components/cronet/ios/cronet_global_state_ios.mm
index 92a7139..a9e00b9 100644
--- a/components/cronet/ios/cronet_global_state_ios.mm
+++ b/components/cronet/ios/cronet_global_state_ios.mm
@@ -75,7 +75,7 @@
   return nullptr;
 }
 
-std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     net::NetLog* net_log) {
   return nullptr;
diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc
index 8e285f1..941a547 100644
--- a/components/download/internal/common/download_response_handler.cc
+++ b/components/download/internal/common/download_response_handler.cc
@@ -82,12 +82,9 @@
 
 void DownloadResponseHandler::OnReceiveResponse(
     const network::ResourceResponseHead& head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   create_info_ = CreateDownloadCreateInfo(head);
-
-  if (ssl_info)
-    cert_status_ = ssl_info->cert_status;
+  cert_status_ = head.cert_status;
 
   // TODO(xingliu): Do not use http cache.
   // Sets page transition type correctly and call
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index e6cd589..ab961f31 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -28,7 +28,6 @@
   // network::mojom::URLLoaderClient
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {}
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override {}
@@ -190,11 +189,9 @@
       download::DownloadSource::NAVIGATION, std::move(url_chain));
 
   // Simulate on the new URLLoaderClient calls that happened on the old client.
-  net::SSLInfo info;
-  info.cert_status = cert_status;
+  response->head.cert_status = cert_status;
   url_loader_client_->OnReceiveResponse(
-      response->head, base::Optional<net::SSLInfo>(info),
-      network::mojom::DownloadedTempFilePtr());
+      response->head, network::mojom::DownloadedTempFilePtr());
 
   // Bind the new client.
   url_loader_client_binding_ =
diff --git a/components/download/public/common/download_response_handler.h b/components/download/public/common/download_response_handler.h
index a100d0a..01050748 100644
--- a/components/download/public/common/download_response_handler.h
+++ b/components/download/public/common/download_response_handler.h
@@ -51,7 +51,6 @@
   // network::mojom::URLLoaderClient
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override;
diff --git a/components/network_time/network_time_test_utils.cc b/components/network_time/network_time_test_utils.cc
index 05ade0b2..d5016d2 100644
--- a/components/network_time/network_time_test_utils.cc
+++ b/components/network_time/network_time_test_utils.cc
@@ -20,33 +20,35 @@
 
 // Update as follows:
 //
-// curl http://clients2.google.com/time/1/current?cup2key=1:123123123
+// curl -i http://clients2.google.com/time/1/current?cup2key=2:123123123
 //
-// where 1 is the key version and 123123123 is the nonce.  Copy the
+// where 2 is the key version and 123123123 is the nonce.  Copy the
 // response and the x-cup-server-proof header into
 // |kGoodTimeResponseBody| and |kGoodTimeResponseServerProofHeader|
 // respectively, and the 'current_time_millis' value of the response
 // into |kGoodTimeResponseHandlerJsTime|.
-const char kGoodTimeResponseBody[] =
-    ")]}'\n"
-    "{\"current_time_millis\":1461621971825"
-    ",\"server_nonce\":-6."
-    "006853099049523E85}";
-const char kGoodTimeResponseServerProofHeader[] =
-    "304402202e0f24db1ea69f1bbe81da4108f381fcf7a2781c53cf7663cb47083cb5fe8e"
-    "fd"
-    "022009d2b67c0deceaaf849f7c529be96701ed5f15d5efcaf401a94e0801accc9832:"
-    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
-const double kGoodTimeResponseHandlerJsTime = 1461621971825;
+const char* kGoodTimeResponseBody[] = {
+    ")]}'\n{\"current_time_millis\":1522081016324,"
+    "\"server_nonce\":-1.475187036492045E154}",
+    ")]}'\n{\"current_time_millis\":1522096305984,"
+    "\"server_nonce\":-1.1926302260014708E-276}"};
+const char* kGoodTimeResponseServerProofHeader[] = {
+    "3046022100c0351a20558bac037253f3969547f82805b340f51de06461e83f33b41f8e85d3"
+    "022100d04162c448438e5462df4bf6171ef26c53ec7d3a0cb915409e8bec6c99c69c67:"
+    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+    "304402201758cc66f7be58692362dad351ee71ecce78bd8491c8bfe903da39ea048ff67d02"
+    "203aa51acfac9462b19ef3e6d6c885a60cb0858a274ae97506934737d8e66bc081:"
+    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
+const double kGoodTimeResponseHandlerJsTime[] = {1522081016324, 1522096305984};
 
 std::unique_ptr<net::test_server::HttpResponse> GoodTimeResponseHandler(
     const net::test_server::HttpRequest& request) {
   net::test_server::BasicHttpResponse* response =
       new net::test_server::BasicHttpResponse();
   response->set_code(net::HTTP_OK);
-  response->set_content(kGoodTimeResponseBody);
+  response->set_content(kGoodTimeResponseBody[0]);
   response->AddCustomHeader("x-cup-server-proof",
-                            kGoodTimeResponseServerProofHeader);
+                            kGoodTimeResponseServerProofHeader[0]);
   return std::unique_ptr<net::test_server::HttpResponse>(response);
 }
 
diff --git a/components/network_time/network_time_test_utils.h b/components/network_time/network_time_test_utils.h
index e9dd537..656ed47 100644
--- a/components/network_time/network_time_test_utils.h
+++ b/components/network_time/network_time_test_utils.h
@@ -28,22 +28,22 @@
 
 namespace network_time {
 
-// The body of a valid time response. Can be returned, with
+// The bodies of sample valid time responses. Can be returned, with
 // |kGoodTimeResponseServerProofHeader|, in responses from test servers
-// to simulate a network time server. This response uses 1 as the key
+// to simulate a network time server. This response uses kKeyVersion as the key
 // version and 123123123 as the nonce. Use
 // NetworkTimeTracker::OverrideNonceForTesting() to set the nonce so
 // that this response validates.
-extern const char kGoodTimeResponseBody[];
+extern const char* kGoodTimeResponseBody[2];
 
-// The x-cup-server-proof header value that should be served along with
+// The x-cup-server-proof header values that should be served along with
 // |kGoodTimeResponseBody| to make a test server response be accepted by
 // NetworkTimeTracker as a valid response.
-extern const char kGoodTimeResponseServerProofHeader[];
+extern const char* kGoodTimeResponseServerProofHeader[2];
 
-// The time that |kGoodTimeResponseBody| uses. Can be converted to a
+// The times that |kGoodTimeResponseBody| uses. Can be converted to a
 // base::Time with base::Time::FromJsTime.
-extern const double kGoodTimeResponseHandlerJsTime;
+extern const double kGoodTimeResponseHandlerJsTime[2];
 
 // Returns a valid network time response using the constants above. See
 // comments in the .cc for how to update the time returned in the response.
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc
index ac66387..20205d43 100644
--- a/components/network_time/network_time_tracker.cc
+++ b/components/network_time/network_time_tracker.cc
@@ -125,16 +125,16 @@
 const char kVariationsServiceFetchBehavior[] = "FetchBehavior";
 
 // This is an ECDSA prime256v1 named-curve key.
-const int kKeyVersion = 1;
+const int kKeyVersion = 2;
 const uint8_t kKeyPubBytes[] = {
     0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
     0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
-    0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36,
-    0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36,
-    0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec,
-    0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b,
-    0xc3, 0xc6, 0xa4, 0x7b, 0xa4, 0x41, 0xfc, 0xa7, 0x02, 0x54, 0xab, 0xe3,
-    0xe4, 0xb1, 0x00, 0xf5, 0xd5, 0x09, 0x11};
+    0x42, 0x00, 0x04, 0xc9, 0xde, 0x8e, 0x72, 0x05, 0xb8, 0xb9, 0xec, 0xa4,
+    0x26, 0xc8, 0x0d, 0xd9, 0x05, 0x59, 0x67, 0xad, 0xd7, 0xf5, 0xf0, 0x46,
+    0xe4, 0xab, 0xe9, 0x81, 0x67, 0x8b, 0x9d, 0x2a, 0x21, 0x68, 0x22, 0xfe,
+    0x83, 0xed, 0x9f, 0x80, 0x19, 0x4f, 0xc5, 0x24, 0xac, 0x12, 0x66, 0xc4,
+    0x4e, 0xf6, 0x8f, 0x54, 0xb5, 0x0c, 0x49, 0xe9, 0xa5, 0xf1, 0x40, 0xfd,
+    0xd9, 0x1a, 0x92, 0x90, 0x8a, 0x67, 0x15};
 
 std::string GetServerProof(const net::URLFetcher* source) {
   const net::HttpResponseHeaders* response_headers =
diff --git a/components/network_time/network_time_tracker_unittest.cc b/components/network_time/network_time_tracker_unittest.cc
index 07b52060..c29c92c3 100644
--- a/components/network_time/network_time_tracker_unittest.cc
+++ b/components/network_time/network_time_tracker_unittest.cc
@@ -475,7 +475,8 @@
   EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
             tracker_->GetNetworkTime(&out_network_time, nullptr));
   EXPECT_EQ(base::Time::UnixEpoch() +
-                base::TimeDelta::FromMilliseconds(1461621971825),
+                base::TimeDelta::FromMilliseconds(
+                    (uint64_t)kGoodTimeResponseHandlerJsTime[0]),
             out_network_time);
   // Should see no backoff in the success case.
   EXPECT_EQ(base::TimeDelta::FromMinutes(60),
@@ -503,7 +504,8 @@
   EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
             tracker_->GetNetworkTime(&out_network_time, nullptr));
   EXPECT_EQ(base::Time::UnixEpoch() +
-                base::TimeDelta::FromMilliseconds(1461621971825),
+                base::TimeDelta::FromMilliseconds(
+                    (uint64_t)kGoodTimeResponseHandlerJsTime[0]),
             out_network_time);
   // Should see no backoff in the success case.
   EXPECT_EQ(base::TimeDelta::FromMinutes(60),
@@ -531,7 +533,8 @@
   EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
             tracker_->GetNetworkTime(&out_network_time, nullptr));
   EXPECT_EQ(base::Time::UnixEpoch() +
-                base::TimeDelta::FromMilliseconds(1461621971825),
+                base::TimeDelta::FromMilliseconds(
+                    (uint64_t)kGoodTimeResponseHandlerJsTime[0]),
             out_network_time);
   // Should see no backoff in the success case.
   EXPECT_EQ(base::TimeDelta::FromMinutes(60),
@@ -838,74 +841,38 @@
   base::Time GetTimeAtIndex(unsigned int i);
 
  private:
-  // |kJsTimes|, |kTimeResponseBodies|, and |kTimeProofHeaders| contain signed
-  // responses for three subsequent time queries served by
-  // MultipleGoodTimeResponseHandler. (That is, kJsTimes[i] is the timestamp
-  // contained in kTimeResponseBodies[i] with signature in kTimeProofHeader[i].)
-  // NetworkTimeTrackerTest.TimeBetweenFetchesHistogram expects that each
-  // timestamp is greater than the one before it.
-  //
-  // Update as follows:
-  //
-  // curl -v http://clients2.google.com/time/1/current?cup2key=1:123123123
-  //
-  // where 1 is the key version and 123123123 is the nonce.  Copy the
-  // response and the x-cup-server-proof header into
-  // |kTimeResponseBodies| and |kTimeProofHeaders| respectively, and the
-  // 'current_time_millis' value of the response into |kJsTimes|.
-  static const double kJsTimes[];
-  static const char* kTimeResponseBodies[];
-  static const char* kTimeProofHeaders[];
-
-  // The index into |kJsTimes|, |kTimeResponseBodies|, and
-  // |kTimeProofHeaders| that will be used in the response in the next
-  // ResponseHandler() call.
+  // The index into |kGoodTimeResponseHandlerJsTime|, |kGoodTimeResponseBody|,
+  // and |kGoodTimeResponseServerProofHeaders| that will be used in the
+  // response in the next ResponseHandler() call.
   unsigned int next_time_index_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(MultipleGoodTimeResponseHandler);
 };
 
-const double MultipleGoodTimeResponseHandler::kJsTimes[] = {1481653709754,
-                                                            1481653820879};
-const char* MultipleGoodTimeResponseHandler::kTimeResponseBodies[] = {
-    ")]}'\n"
-    "{\"current_time_millis\":1481653709754,\"server_nonce\":-2."
-    "7144232419525693E172}",
-    ")]}'\n"
-    "{\"current_time_millis\":1481653820879,\"server_nonce\":1."
-    "8874633267958474E185}"};
-const char* MultipleGoodTimeResponseHandler::kTimeProofHeaders[] = {
-    "3045022006fdfa882460cd43e15b11d7d35cfc3805b0662c558f6efe54f9bf0c38e80650"
-    "0221009777817152b6cc1c2b2ea765104a1ab6b87a4da1e87686ae0641c25b23161ea8:"
-    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-    "3045022100b6ebcf0f2f5c42bb18bd097a60c4204dd2ed29cad4992b5fdfcf1b32bdfdc6"
-    "58022005b378c27dd3ddb6edacce39edc8b4ecf189dff5b64ce99975859f6cdc984e20:"
-    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
-
 std::unique_ptr<net::test_server::HttpResponse>
 MultipleGoodTimeResponseHandler::ResponseHandler(
     const net::test_server::HttpRequest& request) {
   net::test_server::BasicHttpResponse* response =
       new net::test_server::BasicHttpResponse();
 
-  if (next_time_index_ >=
-      arraysize(MultipleGoodTimeResponseHandler::kJsTimes)) {
+  if (next_time_index_ >= arraysize(kGoodTimeResponseBody)) {
     response->set_code(net::HTTP_BAD_REQUEST);
     return std::unique_ptr<net::test_server::HttpResponse>(response);
   }
 
   response->set_code(net::HTTP_OK);
-  response->set_content(kTimeResponseBodies[next_time_index_]);
-  response->AddCustomHeader("x-cup-server-proof",
-                            kTimeProofHeaders[next_time_index_]);
+  response->set_content(kGoodTimeResponseBody[next_time_index_]);
+  response->AddCustomHeader(
+      "x-cup-server-proof",
+      kGoodTimeResponseServerProofHeader[next_time_index_]);
   next_time_index_++;
   return std::unique_ptr<net::test_server::HttpResponse>(response);
 }
 
 base::Time MultipleGoodTimeResponseHandler::GetTimeAtIndex(unsigned int i) {
-  if (i >= arraysize(kJsTimes))
+  if (i >= arraysize(kGoodTimeResponseHandlerJsTime))
     return base::Time();
-  return base::Time::FromJsTime(kJsTimes[i]);
+  return base::Time::FromJsTime(kGoodTimeResponseHandlerJsTime[i]);
 }
 
 }  // namespace
diff --git a/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc b/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc
index cc6065e..8c1d7259 100644
--- a/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/reading_list/reading_list_suggestions_provider_unittest.cc
@@ -30,11 +30,8 @@
 class ReadingListSuggestionsProviderTest : public ::testing::Test {
  public:
   ReadingListSuggestionsProviderTest() {
-    std::unique_ptr<base::SimpleTestClock> clock =
-        std::make_unique<base::SimpleTestClock>();
-    clock_ = clock.get();
     model_ = std::make_unique<ReadingListModelImpl>(
-        /*storage_layer=*/nullptr, /*pref_service=*/nullptr, std::move(clock));
+        /*storage_layer=*/nullptr, /*pref_service=*/nullptr, &clock_);
   }
 
   void CreateProvider() {
@@ -56,23 +53,23 @@
   void AddEntries() {
     model_->AddEntry(url_unread1_, kTitleUnread1,
                      reading_list::ADDED_VIA_CURRENT_APP);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(url_unread2_, kTitleUnread2,
                      reading_list::ADDED_VIA_CURRENT_APP);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(url_read1_, kTitleRead1,
                      reading_list::ADDED_VIA_CURRENT_APP);
     model_->SetReadStatus(url_read1_, true);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(url_unread3_, kTitleUnread3,
                      reading_list::ADDED_VIA_CURRENT_APP);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(url_unread4_, kTitleUnread4,
                      reading_list::ADDED_VIA_CURRENT_APP);
   }
 
  protected:
-  base::SimpleTestClock* clock_;
+  base::SimpleTestClock clock_;
   std::unique_ptr<ReadingListModelImpl> model_;
   testing::StrictMock<MockContentSuggestionsProviderObserver> observer_;
   std::unique_ptr<ReadingListSuggestionsProvider> provider_;
@@ -117,7 +114,7 @@
   std::string title_read1 = "title_read1";
   model_->AddEntry(url_unread1, title_unread1,
                    reading_list::ADDED_VIA_CURRENT_APP);
-  clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+  clock_.Advance(base::TimeDelta::FromMilliseconds(10));
   model_->AddEntry(url_read1, title_read1, reading_list::ADDED_VIA_CURRENT_APP);
   model_->SetReadStatus(url_read1, true);
 
diff --git a/components/policy/resources/policy_templates_gu.xtb b/components/policy/resources/policy_templates_gu.xtb
index b7ece74..dcf6e2d 100644
--- a/components/policy/resources/policy_templates_gu.xtb
+++ b/components/policy/resources/policy_templates_gu.xtb
@@ -772,6 +772,18 @@
           જ્યારે આ નીતિ સેટ કરેલ ન હોય, ત્યારે વધુ-ચોક્કસ નીતિઓના વર્તન પર પ્રભાવ પડતો નથી.</translation>
 <translation id="2987155890997901449">ARC સક્ષમ કરે છે</translation>
 <translation id="2987227569419001736">વેબ Bluetooth API નો ઉપયોગ નિયંત્રિત કરો</translation>
+<translation id="2998886474614739865">
+      નોંધ: આ નીતિ પ્રયોગાત્મક છે અને તે કદાચ કાર્યપ્રણાલીને વેરવિખેર કરી શકે છે!
+      આ નીતિ સાઇન-ઇન સ્ક્રીન પર લાગુ થાય છે. કૃપા કરીને <ph name="ISOLATE_ORIGINS_POLICY_NAME" /> નીતિ પણ જુઓ, જે વપરાશકર્તા સત્ર પર લાગુ થાય છે. બન્ને નીતિઓને સમાન મૂલ્ય પર સેટ કરવાની ભલામણ કરવામાં આવે છે. જો મૂલ્યો મેળ નહીં ખાય, તો વપરાશકર્તા સત્રમાં દાખલ થતા દરમ્યાન વપરાશકર્તા નીતિ દ્વારા નિર્દિષ્ટ મૂલ્ય લાગુ કરવામાં આવે ત્યારે વિલંબ થઈ શકે છે.
+      જો આ નીતિ ચાલુ કરવામાં આવશે, તો અલ્પવિરામથી છૂટી પાડેલી
+      સૂચિમાંની જણાવેલ ઑરિજિનની દરેક તેની પોતાની પ્રક્રિયામાં ચાલશે. આનાથી સબડોમેન
+      અનુસાર જણાવાયેલ ઑરિજિન પણ આઇસોલેટ થશે; દા.ત. ઉલ્લેખિત https://example.com\
+      ના કારણે https://foo.example.com/ પણ https://example.com/ સાઇટના એક ભાગ તરીકે
+      આઇસોલેટ થશે.
+      જો આ નીતિ બંધ કરવામાં આવશે, તો સાઇટ દીઠ આઇસોલેશન પ્રક્રિયા મેનેજમેન્ટ તર્કનો અમલ
+      થશે.
+      જો આ નીતિ ગોઠવવામાં ન આવી હોય, તો સાઇન-ઇન સ્ક્રીન માટે પ્લૅટફૉર્મ ડિફૉલ્ટ સાઇટ આઇસોલેશન સેટિંગનો ઉપયોગ કરવામાં આવશે.
+      </translation>
 <translation id="3016255526521614822">વ્હાઇટલિસ્ટ નોંધ લેતી ઍપની <ph name="PRODUCT_OS_NAME" />ના લૉક સ્ક્રીન પર મંજૂરી છે</translation>
 <translation id="3021562480854470924">રોલબૅક માટે મંજૂરી આપવામાં આવેલ માઇલસ્ટોનની સંખ્યા</translation>
 <translation id="3030000825273123558">મેટ્રિક્સ રિપોર્ટિંગને સક્ષમ કરે છે</translation>
@@ -889,6 +901,18 @@
 
           જો આ નીતિ ખાલી ન હોય તેવી સ્ટ્રિંગ પર સેટ કરેલી હશે, તો તે સ્ટ્રિંગનો ઉપયોગ <ph name="PRODUCT_NAME" /> ગંતવ્યના નામ તરીકે થશે. અન્યથા, ગંતવ્યનું નામ ઉપકરણનું નામ હશે. જો આ નીતિ સેટ કરેલી નહીં હોય, તો ગંતવ્યનું નામ ઉપકરણનું નામ હશે અને તે ઉપકરણના માલિકને (અથવા ઉપકરણ મેનેજ કરતા ડોમેનના વપરાશકર્તાને) તેને બદલવાની મંજૂરી હશે. નામ 24 અક્ષરો સુધી મર્યાદિત હોય છે.</translation>
 <translation id="3381968327636295719">ડિફૉલ્ટ રૂપે હોસ્ટ બ્રાઉઝરનો ઉપયોગ કરો</translation>
+<translation id="3386001018488754001">
+      નોંધ: આ નીતિ પ્રયોગાત્મક છે અને તે કદાચ કાર્યપ્રણાલીને વેરવિખેર કરી શકે છે!
+      આ નીતિ સાઇન-ઇન સ્ક્રીન પર લાગુ થાય છે. કૃપા કરીને <ph name="SITE_PER_PROCESS_POLICY_NAME" /> નીતિ પણ જુઓ, જે વપરાશકર્તા સત્ર પર લાગુ થાય છે. બન્ને નીતિને સમાન મૂલ્ય પર સેટ કરવા માટેની ભલામણ કરવામાં આવે છે. જો મૂલ્યો મેળ નહીં ખાય, તો વપરાશકર્તા સત્રમાં દાખલ થતા દરમ્યાન વપરાશકર્તા નીતિ દ્વારા નિર્દિષ્ટ મૂલ્ય લાગુ કરવામાં આવે ત્યારે વિલંબ થઈ શકે છે.
+      તમે જેને આઇસોલેટ કરવા ઈચ્છો છો તે સાઇટોની સૂચિ વડે IsolateOriginsનો ઉપયોગ કરીને
+      વપરાશકર્તા માટે આઇસોલેશન અને મર્યાદિત અસર એમ બન્નેમાં સર્વોત્તમ મેળવવા માટે
+      IsolateOriginsની નીતિ સેટિંગ જોઈ શકો છો. આ SitePerProcess સેટિંગ બધી સાઇટને
+      આઇસોલેટ કરે છે.
+      જો આ નીતિ ચાલુ કરવામાં આવશે, તો દરેક સાઇટ તેની પોતાની પ્રક્રિયામાં ચાલશે.
+      જો આ નીતિ બંધ કરવામાં આવશે, તો સાઇટ દીઠ આઇસોલેશન પ્રક્રિયા મેનેજમેન્ટ તર્કનો અમલ
+      થશે.
+      જો આ નીતિ ગોઠવવામાં ન આવી હોય, તો વપરાશકર્તા આ સેટિંગ બદલી શકશે.
+      </translation>
 <translation id="3395348522300156660">વપરાશકર્તા ઉપયોગમાં લઈ શકે તે પ્રિન્ટરને ઉલ્લેખિત કરે છે.
 
       જો <ph name="PRINTERS_WHITELIST" />ને <ph name="DEVICE_PRINTERS_ACCESS_MODE" /> માટે પસંદ કરી હોય, તો જ આ નીતિનો ઉપયોગ કરવામાં આવે છે
@@ -934,6 +958,10 @@
           જો આ નીતિ ખોટાં પર સેટ થયેલી હોય અથવા સેટ કર્યાં વગર છોડેલી હોય, તો પાવર મેનેજમેન્ટમાં વિલંબ થાય છે અને સત્ર લંબાઈ મર્યાદા સત્ર પ્રારંભ થતાં તરત જ ચાલવાનો પ્રારંભ કરશે.</translation>
 <translation id="3478024346823118645">સાઇન આઉટ કરવા પર વપરાશકર્તા ડેટા સાફ કરો</translation>
 <translation id="348495353354674884">વર્ચ્યુઅલ કીબોર્ડને અક્ષમ કરો</translation>
+<translation id="3487623755010328395">
+        જો આ નીતિ સેટ કરેલી હશે, તો <ph name="PRODUCT_NAME" /> પોતાને રજિસ્ટર કરવાનો પ્રયાસ કરશે અને બધી પ્રોફાઇલ માટે સંકળાયેલ ક્લાઉડ નીતિ લાગુ કરશે.
+
+        આ નીતિનું મૂલ્ય નોંધણી ટોકન છે, જે Google Admin console પરથી પુનઃપ્રાપ્ત કરી શકાય છે.</translation>
 <translation id="3489247539215560634">જો આ સેટિંગ સક્ષમ હોય, તો વપરાશકર્તાઓ <ph name="PRODUCT_NAME" /> યાદ રાખેલ પાસવર્ડ ધરાવી અને જ્યારે તેઓ આગલી વખતે સાઇટમાં લૉગ ઇન કરે ત્યારે તેમને આપમેળે પ્રદાન કરી શકે છે.
 
           જો આ સેટિંગ્સ અક્ષમ કરેલ હોય, તો વપરાશકર્તાઓ નવા પાસવર્ડ સાચવી શકતાં પરંતુ તેઓ હજુ
@@ -1646,6 +1674,18 @@
 
       જો નીતિ સેટ કરેલ નથી અથવા જો તે ખાલી સ્ટ્રિંગ અથવા અમાન્ય પોર્ટ શ્રેણી પર સેટ કરેલ હોય, તો WebRTC ને કોઈપણ ઉપલબ્ધ સ્થાનિક UDP પોર્ટને ઉપયોગમાં લેવાની મંજૂરી આપવામાં આવે છે.</translation>
 <translation id="5290940294294002042">પ્લગિંસની તે સૂચિનો ઉલ્લેખ કરો કે વપરાશાકર્તા જેને સક્ષમ અથવા અક્ષમ કરી શકે</translation>
+<translation id="5301787427319106606">
+      નોંધ: આ નીતિ પ્રયોગાત્મક છે અને તે કદાચ કાર્યપ્રણાલીને વેરવિખેર કરી શકે છે!
+      તમે જેને આઇસોલેટ કરવા ઈચ્છો છો તે સાઇટોની સૂચિ વડે IsolateOriginsનો ઉપયોગ કરીને
+      વપરાશકર્તા માટે આઇસોલેશન અને મર્યાદિત અસર એમ બન્નેમાં સર્વોત્તમ મેળવવા માટે
+      IsolateOriginsની નીતિ સેટિંગ જોઈ શકો છો. આ SitePerProcess સેટિંગ બધી સાઇટને
+      આઇસોલેટ કરે છે.
+      જો આ નીતિ ચાલુ કરવામાં આવશે, તો દરેક સાઇટ તેની પોતાની પ્રક્રિયામાં ચાલશે.
+      જો આ નીતિ બંધ કરવામાં આવશે, તો સાઇટ દીઠ આઇસોલેશન પ્રક્રિયા મેનેજમેન્ટ તર્કનો અમલ
+      થશે.
+      જો આ નીતિ ગોઠવવામાં આવી ન હોય, તો વપરાશકર્તા આ સેટિંગ બદલી શકશે.
+      <ph name="PRODUCT_OS_NAME" /> પર, ભલામણ કરવામાં આવી છે કે <ph name="DEVICE_LOGIN_SCREEN_SITE_PER_PROCESS_POLICY_NAME" /> ઉપકરણ નીતિને પણ સમાન મૂલ્ય પર સેટ કરો. જો બન્ને નીતિઓ દ્વારા નિર્દિષ્ટ મૂલ્યો મેળ નહીં ખાય, તો વપરાશકર્તા સત્રમાં દાખલ થતા દરમ્યાન વપરાશકર્તા નીતિ દ્વારા નિર્દિષ્ટ મૂલ્ય લાગુ કરવામાં આવે ત્યારે વિલંબ થઈ શકે છે.
+      </translation>
 <translation id="5302612588919538756">આ નીતિ ટાળવામાં આવી છે, તેને બદલે SyncDisabled નો ઉપયોગ કરવાનું ધ્યાનમાં લો.
 
       વપરાશકર્તાને <ph name="PRODUCT_NAME" /> પર સાઇન ઇન કરવાની મંજૂરી આપે છે.
@@ -2303,6 +2343,14 @@
 <translation id="7070525176564511548">દર અઠવાડિયે (168 કલાકે) પાસવર્ડ એન્ટ્રી જરૂરી છે</translation>
 <translation id="7072208053150563108">મશીન પાસવર્ડ બદલવાનો દર</translation>
 <translation id="7072406291414141328">થ્રોટલિંગ નેટવર્ક બૅન્ડવિડ્થને સક્ષમ કરે છે</translation>
+<translation id="7074513465313721551">ડોમેનની એ સૂચિ ગોઠવો, જેના પર સુરક્ષિત બ્રાઉઝિંગ વિશ્વાસ કરશે. આનો અર્થ છે કે:
+      જો જોખમી સંસાધનો (દા.ત. ફિશિંગ, માલવેર, અથવા ન જોઈતા સૉફ્ટવેર)ની URLs આ ડોમેન સાથે મેળ ખાશે તો સુરક્ષિત બ્રાઉઝિંગ તેમની તપાસ નહીં કરે.
+      સુરક્ષિત બ્રાઉઝિંગની ડાઉનલોડ સુરક્ષા સેવા આ ડોમેન પર હોસ્ટ કરાતા ડાઉનલોડની તપાસ નહીં કરે.
+      જો પેજની URL આ ડોમેન સાથે મેળ ખાશે, તો સુરક્ષિત બ્રાઉઝિંગની પાસવર્ડ સુરક્ષા સેવા પાસવર્ડના ફરીથી ઉપયોગની તપાસ નહીં કરે.
+
+      જો આ સેટિંગ ચાલુ કરેલી હશે, તો સુરક્ષિત બ્રાઉઝિંગ આ ડોમેનનો વિશ્વાસ કરશે.                 
+      જો આ સેટિંગ બંધ કરી હોય અથવા સેટ નહીં કરી હોય, તો બધા સંસાધનો પર ડિફૉલ્ટ સુરક્ષિત બ્રાઉઝિંગ સુરક્ષા લાગુ કરવામાં આવે છે.
+      આ નીતિ <ph name="MS_AD_NAME" /> ડોમેન સાથે જોડાયેલ ન હોય તેવી Windows આવૃત્તિઓ પર ઉપલબ્ધ નથી.</translation>
 <translation id="7079519252486108041">આ સાઇટ્સ પર પોપ-અપ્સને અવરોધિત કરો</translation>
 <translation id="7106631983877564505">જ્યારે <ph name="PRODUCT_OS_NAME" /> ઉપકરણો નિષ્ક્રિય અથવા સસ્પેન્ડ થાય ત્યારે લૉકને સક્ષમ કરે છે.
 
diff --git a/components/policy/resources/policy_templates_iw.xtb b/components/policy/resources/policy_templates_iw.xtb
index 9437ad4..c7565c5 100644
--- a/components/policy/resources/policy_templates_iw.xtb
+++ b/components/policy/resources/policy_templates_iw.xtb
@@ -648,6 +648,16 @@
           ערך המדיניות צריך להיות באלפיות שנייה. הערכים מצומצמים כך שיהיו קטנים ממשך ההשהיה לפני מצב לא פעיל.</translation>
 <translation id="2987155890997901449">‏הפעל את ARC</translation>
 <translation id="2987227569419001736">‏שליטה על השימוש ב-Web Bluetooth API</translation>
+<translation id="2998886474614739865">‏
+      הערה: המדיניות הזו ניסיונית ועלולות להתרחש בה תקלות!
+      המדיניות הזו חלה על מסך הכניסה. יש לעיין גם במדיניות <ph name="ISOLATE_ORIGINS_POLICY_NAME" /> שחלה על הסשן של המשתמש. מומלץ לקבוע את אותו ערך בשתי הגדרות המדיניות. אם הערכים יהיו שונים, ייתכן עיכוב בכניסה לסשן של משתמש כשהמערכת מחילה את הערך שצוין על-ידי מדיניות המשתמש.
+      אם המדיניות מופעלת, כל אחד מהמקורות שצוינו ברשימה המופרדת באמצעות פסיקים יפעל       
+      בתהליך משלו. ההגדרה הזו תבודד גם מקורות שהשם שלהם הוא תת-דומיין. לדוגמה, ציון 
+      הכתובת https://example.com/‎ יגרום גם לבידוד של https://foo.example.com/‎ כחלק       
+      מהאתר https://example.com/‎.
+      אם המדיניות מושבתת, תחול הלוגיקה של ניהול תהליך בידוד לכל אתר בנפרד.
+      אם המדיניות לא מוגדרת, על מסך הכניסה יחולו הגדרות בידוד האתרים שנקבעו כברירת מחדל בפלטפורמה.
+      </translation>
 <translation id="3016255526521614822">הוסף לרשימת ההיתרים אפליקציות לרישום הערות שמותרות במסך הנעילה של <ph name="PRODUCT_OS_NAME" /></translation>
 <translation id="3021562480854470924">מספר הגירסאות הקודמות שאפשר לחזור אליהן</translation>
 <translation id="3030000825273123558">הפעל דיווח על מדדים</translation>
@@ -750,6 +760,16 @@
 
           אם במדיניות הזו הוגדרה מחרוזת שאינה ריקה, אותה מחרוזת תשמש כשם היעד של <ph name="PRODUCT_NAME" />. אחרת, שם היעד יהיה שם המכשיר. אם המדיניות הזו לא מוגדרת, שם היעד יהיה שם המכשיר, ובעל המכשיר (או משתמש מהדומיין שמנהל את המכשיר) יוכל לשנות אותו. השם מוגבל ל-24 תווים.</translation>
 <translation id="3381968327636295719">השתמש בדפדפן המארח כברירת מחדל</translation>
+<translation id="3386001018488754001">‏
+      הערה: המדיניות הזו ניסיונית ועלולות להתרחש בה תקלות!
+      המדיניות הזו חלה על מסך הכניסה. יש לעיין גם במדיניות <ph name="SITE_PER_PROCESS_POLICY_NAME" /> שחלה על הסשן של המשתמש. מומלץ לקבוע את אותו ערך בשתי הגדרות המדיניות. אם הערכים יהיו שונים, ייתכן עיכוב בכניסה לסשן של משתמש כשהמערכת מחילה את הערך שצוין על-ידי מדיניות המשתמש.
+      מומלץ לעיין בהגדרת המדיניות IsolateOrigins כדי ליהנות מהיתרונות של שתי האפשרויות -       
+      בידוד והשפעה מוגבלת על משתמשים - על-ידי שימוש ב-IsolateOrigins עם רשימה של 
+      האתרים שברצונך לבודד. ההגדרה הזו, SitePerProcess, מבודדת את כל האתרים. 
+      אם המדיניות מופעלת, כל אתר יפעל בתהליך משלו.
+      אם המדיניות מושבתת, תחול הלוגיקה של ניהול תהליך בידוד לכל אתר בנפרד.
+      אם המדיניות לא מוגדרת, המשתמש יוכל לשנות את ההגדרה הזו.
+      </translation>
 <translation id="3395348522300156660">מציינת את המדפסות הזמינות למשתמש.
 
       המדיניות הזו מופעלת רק אם האפשרות <ph name="PRINTERS_WHITELIST" /> נבחרה בשביל <ph name="DEVICE_PRINTERS_ACCESS_MODE" />
@@ -787,6 +807,10 @@
 אם המדיניות מוגדרת כ-false, או אינה מוגדרת כלל, הגבלת אורך ההפעלה והשהיית ניהול צריכת החשמל מתחילות לרוץ מיד בתחילת ההפעלה.</translation>
 <translation id="3478024346823118645">מחק נתוני משתמש בעת יציאה</translation>
 <translation id="348495353354674884">הפעל מקלדת וירטואלית</translation>
+<translation id="3487623755010328395">‏
+        אם המדיניות הזו מוגדרת, <ph name="PRODUCT_NAME" /> ינסה לרשום את עצמו ולהחיל מדיניות ענן משויכת על כל הפרופילים.
+
+        ערך המדיניות הזו הוא אסימון הרשמה שאפשר לאחזר מהמסוף בממשק Google למנהלי מערכות.</translation>
 <translation id="3496296378755072552">מנהל הסיסמאות</translation>
 <translation id="350443680860256679">‏הגדר ARC</translation>
 <translation id="3504791027627803580">‏מדיניות זו מציינת את כתובת האתר של מנוע החיפוש שנעשה בו שימוש לביצוע חיפוש תמונות. בקשות החיפוש יישלחו באמצעות שיטת GET. אם מוגדרת המדיניות DefaultSearchProviderImageURLPostParams, בקשות לחיפוש תמונות יישלחו במקום זאת באמצעות שיטת POST.
@@ -1355,6 +1379,16 @@
 
       אם המדיניות לא מוגדרת, או אם היא מוגדרת למחרוזת ריקה או לטווח יציאות לא חוקי, כל יציאות UDP המקומיות שזמינות מותרות לשימוש ב-WebRTC.</translation>
 <translation id="5290940294294002042">ציין רשימה של יישומי פלאגין שהמשתמש יכול להפעיל או להשבית</translation>
+<translation id="5301787427319106606">‏
+      הערה: המדיניות הזו ניסיונית ועלולות להתרחש בה תקלות!
+      מומלץ לעיין בהגדרת המדיניות IsolateOrigins כדי ליהנות מהיתרונות של שתי האפשרויות -             
+      בידוד והשפעה מוגבלת על משתמשים - על-ידי שימוש ב-IsolateOrigins עם רשימה של 
+      האתרים שברצונך לבודד. ההגדרה הזו, SitePerProcess, מבודדת את כל האתרים. 
+      אם המדיניות מופעלת, כל אתר יפעל בתהליך משלו.
+      אם המדיניות מושבתת, תחול הלוגיקה של ניהול תהליך בידוד לכל אתר בנפרד.
+      אם המדיניות לא מוגדרת, המשתמש יוכל לשנות את ההגדרה הזו.
+      ב-<ph name="PRODUCT_OS_NAME" />, מומלץ גם לקבוע את אותו ערך במדיניות המכשיר <ph name="DEVICE_LOGIN_SCREEN_SITE_PER_PROCESS_POLICY_NAME" />. אם הערכים יהיו שונים, ייתכן עיכוב בכניסה לסשן של משתמש כשהמערכת מחילה את הערך שצוין על-ידי מדיניות המשתמש.
+      </translation>
 <translation id="5302612588919538756">‏מדיניות זו הוצאה משימוש, שקול להשתמש במדיניות SyncDisabled במקומה.
 
       המדיניות מאפשרת למשתמש להיכנס אל <ph name="PRODUCT_NAME" />.
@@ -1904,6 +1938,14 @@
 <translation id="706669471845501145">אפשר לאתרים להציג התראות בשולחן העבודה</translation>
 <translation id="7072208053150563108">תדירות השינוי של סיסמת המחשב</translation>
 <translation id="7072406291414141328">מאפשרת לווסת את רוחב הפס</translation>
+<translation id="7074513465313721551">‏הגדרה של רשימת הדומיינים שייחשבו כמהימנים בגלישה בטוחה. המשמעות:
+      שירות גלישה בטוחה לא יחפש משאבים מסוכנים (כמו דיוג, תוכנות זדוניות או לא רצויות) אם כתובות האתרים שלהם תואמות לדומיינים האלה.
+      שירות הגנת ההורדות של גלישה בטוחה לא יבדוק הורדות שמתארחות בדומיינים האלה.
+      שירות הגנת הסיסמה של גלישה בטוחה לא יבדוק שימוש חוזר בסיסמה אם כתובת האתר של הדף תואמת לדומיינים האלה.
+
+      אם ההגדרה הזו פועלת, שירות גלישה בטוחה יתייחס לדומיינים האלה כבטוחים.
+      אם ההגדרה הזו מושבתת או לא תוגדר, תחול הגנת ברירת המחדל של גלישה בטוחה על כל המשאבים.
+     המדיניות הזו לא זמינה במופעי Windows שלא צורפו אל דומיין <ph name="MS_AD_NAME" />.</translation>
 <translation id="7079519252486108041">חסום חלונות קופצים באתרים אלה</translation>
 <translation id="7106631983877564505">אפשר נעילה כאשר מכשירי <ph name="PRODUCT_OS_NAME" /> אינם פעילים או מושעים.
 
diff --git a/components/policy/resources/policy_templates_ru.xtb b/components/policy/resources/policy_templates_ru.xtb
index 4f4c025..8412a768 100644
--- a/components/policy/resources/policy_templates_ru.xtb
+++ b/components/policy/resources/policy_templates_ru.xtb
@@ -57,6 +57,13 @@
 
       При этом пользователю доступны все принтеры, идентификаторы которых не указаны в правиле.
       </translation>
+<translation id="1181881366217399113">
+      ПРИМЕЧАНИЕ. Это экспериментальная функция, ее использование может привести к сбоям в работе.
+Когда правило включено, для каждого сайта из списка, разделенного запятыми, запускается отдельный процесс. При этом сайты будут изолированы по субдоменам. Например, если указать https://example.com/, будет также изолирован его субдомен https://foo.example.com/.
+Когда правило отключено, используется логика процесса pre-Site Isolation.
+Когда правило не настроено, пользователи могут самостоятельно менять эту настройку.
+Желательно, чтобы значение правила <ph name="DEVICE_LOGIN_SCREEN_ISOLATE_ORIGINS_POLICY_NAME" /> совпадало со значением, установленным в <ph name="PRODUCT_OS_NAME" />. В случае противоречия перед началом сеанса может произойти задержка, так как первым применяется правило, установленное пользователем операционной системы.
+      </translation>
 <translation id="1198465924256827162">Позволяет указать, с какой частотой нужно отправлять данные об устройстве (в миллисекундах).
 
       Если это правило не настроено, значение по умолчанию составляет 3 часа. Минимальное значение – 60 секунд.</translation>
@@ -238,7 +245,12 @@
       Формат значений соответствует названиям часовых поясов в базе данных часовых поясов IANA (см. https://ru.wikipedia.org/wiki/Tz_database). В частности, большинство часовых поясов можно описать по принципу "континент/большой_город" или "океан/большой_город".
 
       Если параметр установлен, это отключает автоматическое обновление часового пояса на основе геоданных и переопределяет правило SystemTimezoneAutomaticDetection.</translation>
+<translation id="1888871729456797026">Токен регистрации облачного правила на компьютере</translation>
 <translation id="1897365952389968758">Разрешить всем сайтам выполнять JavaScript</translation>
+<translation id="1906888171268104594">Регулирует отправку данных в Google (диагностическая информация, статистика использования и отчеты о сбоях).
+Когда правило включено, <ph name="PRODUCT_OS_NAME" /> отправляет соответствующие сведения.
+Когда отключено – данные не отправляются.
+Если значение не установлено, правило применяется к управляемым устройствам по умолчанию.</translation>
 <translation id="193259052151668190">Белый список отсоединяемых USB-устройств</translation>
 <translation id="1933378685401357864">Обои для рабочего стола</translation>
 <translation id="1956493342242507974">Управление электропитанием на экране входа в <ph name="PRODUCT_OS_NAME" />.
@@ -393,6 +405,11 @@
 <translation id="2386362615870139244">Использование блокировки сна</translation>
 <translation id="2411817661175306360">Предупреждения от защиты паролем отключены</translation>
 <translation id="2411919772666155530">Блокировать уведомления на этих сайтах</translation>
+<translation id="2415979855753196119">Позволяет управлять триггером, при срабатывании которого служба защиты паролей предупреждает Google, что аккаунт под угрозой.
+Когда установлено значение "PasswordProtectionRiskOff", триггер не срабатывает и предупреждения не высылаются.
+Когда установлено значение "PasswordProtectionRiskOnPasswordReuse", триггер срабатывает, если пользователь повторно вводит пароль Google на сайте, не внесенном в белый список.
+Когда установлено значение "PasswordProtectionRiskOnPhishingReuse", триггер срабатывает, если пользователь повторно вводит пароль Google на фишинговом сайте.
+Когда значение не установлено, триггер срабатывает при повторном вводе пароля Google на фишинговом сайте, но пользователь может изменить эту настройку самостоятельно.</translation>
 <translation id="2418507228189425036">Отключает сохранение истории в <ph name="PRODUCT_NAME" /> и запрещает пользователям изменять эту настройку.
 
       Если функция включена, история просмотров не сохраняется. Кроме того, отключается синхронизация вкладок.
@@ -576,6 +593,11 @@
 
       Если правило настроено, задания печати, открытые в режиме предварительного просмотра, будут отправляться на системный принтер по умолчанию.</translation>
 <translation id="2867699958489427143">Вернуться к целевой версии и оставаться на ней, если установлена более поздняя версия ОС. В процессе запустить функцию Full Powerwash.</translation>
+<translation id="286802604195763750">Позволяет управлять триггером, при срабатывании которого пользователь получает предупреждение от службы защиты паролей о повторном вводе пароля на подозрительном сайте.
+Когда установлено значение "PasswordProtectionWarningOff", предупреждения не появляются.
+Когда установлено значение "PasswordProtectionWarningOnPasswordReuse", предупреждение от службы защиты паролей появляется, если пользователь повторно вводит пароль Google на сайте, не внесенном в белый список.
+Когда установлено значение "PasswordProtectionWarningOnPhishingReuse", предупреждение от службы защиты паролей появляется, если пользователь повторно вводит пароль Google на фишинговом сайте.
+Когда значение не установлено, предупреждение от службы защиты паролей появляется при повторном вводе пароля Google на фишинговом сайте, но пользователь может изменить эту настройку самостоятельно.</translation>
 <translation id="2872961005593481000">Завершить работу</translation>
 <translation id="2874209944580848064">Примечание для устройств на платформе <ph name="PRODUCT_OS_NAME" />, поддерживающих приложения Android.</translation>
 <translation id="2877225735001246144">Отключить поиск записи CNAME при запросе на аутентификацию Kerberos</translation>
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb
index 8dcaafd1..079cdb4 100644
--- a/components/policy/resources/policy_templates_th.xtb
+++ b/components/policy/resources/policy_templates_th.xtb
@@ -645,6 +645,17 @@
           ค่านโยบายควรกำหนดในหน่วยมิลลิวินาที ค่าจะถูกบีบให้น้อยกว่าหรือเท่ากับระยะหน่วงเวลาการปิดหน้าจอ (หากตั้งค่า) และระยะหน่วงเวลาของการไม่ใช้งาน</translation>
 <translation id="2987155890997901449">เปิดใช้ ARC</translation>
 <translation id="2987227569419001736">ควบคุมการใช้ Web Bluetooth API</translation>
+<translation id="2998886474614739865">
+      หมายเหตุ: นโยบายนี้อยู่ในช่วงทดสอบและอาจส่งผลให้มีการทำงานผิดปกติ
+      นโยบายนี้ใช้กับหน้าจอลงชื่อเข้าใช้ โปรดดูเพิ่มเติมที่นโยบาย <ph name="ISOLATE_ORIGINS_POLICY_NAME" /> ซึ่งใช้กับเซสชันของผู้ใช้ ขอแนะนำให้ตั้งค่าเดียวกันสำหรับทั้ง 2 นโยบาย ค่าที่ไม่ตรงกันอาจทำให้เกิดความล่าช้าเมื่อเข้าสู่เซสชันของผู้ใช้ในขณะที่นำค่าที่นโยบายด้านผู้ใช้ระบุไปใช้
+      หากเปิดใช้นโยบาย ต้นทางแต่ละแห่งที่มีชื่อในรายการ
+      ที่คั่นด้วยจุลภาคจะทำงานตามขั้นตอนของตนเอง และยังเป็นการแยก
+      ต้นทางที่ตั้งชื่อตามโดเมนย่อย เช่น การระบุ https://example.com/ จะ
+      แยก https://foo.example.com/ ด้วย เนื่องจากเป็นส่วนหนึ่งของ
+      เว็บไซต์ https://example.com/
+      หากปิดใช้นโยบาย จะมีการใช้ตรรกะการจัดการขั้นตอนการแยกแบบทีละเว็บไซต์
+      หากไม่ได้กำหนดค่านโยบายนี้ไว้ จะมีการใช้การตั้งค่าเริ่มต้นสำหรับการแยกเว็บไซต์บนแพลตฟอร์มสำหรับหน้าจอการลงชื่อเข้าใช้
+      </translation>
 <translation id="3016255526521614822">อนุญาตพิเศษให้แอปสำหรับจดโน้ตแสดงในหน้าจอล็อกของ <ph name="PRODUCT_OS_NAME" /></translation>
 <translation id="3021562480854470924">อนุญาตให้มีจุดการย้อนกลับ</translation>
 <translation id="3030000825273123558">เปิดใช้งานการรายงานเมตริก</translation>
@@ -748,6 +759,17 @@
 
           หากตั้งค่านโยบายนี้เป็นสตริงที่ไม่ว่างเปล่า ระบบจะใช้สตริงนั้นเป็นชื่อปลายทางของ <ph name="PRODUCT_NAME" /> มิเช่นนั้นชื่อปลายทางจะเป็นชื่ออุปกรณ์ หากไม่ตั้งค่านโยบายนี้ ชื่อปลายทางจะเป็นชื่ออุปกรณ์ และเจ้าของอุปกรณ์ (หรือผู้ใช้จากโดเมนที่จัดการอุปกรณ์) จะได้รับอนุญาตให้เปลี่ยนชื่อ ชื่อต้องมีความยาวไม่เกิน 24 อักขระ</translation>
 <translation id="3381968327636295719">ใช้เบราว์เซอร์โฮสต์โดยค่าเริ่มต้น</translation>
+<translation id="3386001018488754001">
+      หมายเหตุ: นโยบายนี้อยู่ในช่วงทดสอบและอาจส่งผลให้มีการทำงานผิดปกติ
+      นโยบายนี้ใช้กับหน้าจอลงชื่อเข้าใช้ โปรดดูเพิ่มเติมที่นโยบาย <ph name="SITE_PER_PROCESS_POLICY_NAME" /> ซึ่งใช้กับเซสชันของผู้ใช้ ขอแนะนำให้ตั้งค่าเดียวกันสำหรับทั้ง 2 นโยบาย ค่าที่ไม่ตรงกันอาจทำให้เกิดความล่าช้าเมื่อเข้าสู่เซสชันของผู้ใช้ในขณะที่นำค่าที่นโยบายด้านผู้ใช้ระบุไปใช้
+      คุณอาจต้องดูการตั้งค่านโยบาย IsolateOrigins เพื่อให้
+      ได้ผลลัพธ์ที่ดีที่สุดทั้งการแยกและการจำกัดผลกระทบที่มีต่อผู้ใช้ด้วยการใช้
+      IsolateOrigins กับรายการเว็บไซต์ที่คุณต้องการแยก
+      การตั้งค่า SitePerProcess นี้จะแยกเว็บไซต์ทั้งหมด
+      หากเปิดใช้นโยบาย แต่ละเว็บไซต์จะทำงานตามขั้นตอนของตนเอง
+      หากปิดใช้นโยบาย ระบบจะใช้ตรรกะการจัดการขั้นตอนการแยกแบบทีละเว็บไซต์
+      หากไม่ได้กำหนดค่านโยบายไว้ ผู้ใช้จะเปลี่ยนการตั้งค่านี้ได้
+      </translation>
 <translation id="3395348522300156660">ระบุเครื่องพิมพ์ที่ผู้ใช้ใช้งานได้
 
       จะใช้นโยบายนี้ก็ต่อเมื่อเลือก <ph name="PRINTERS_WHITELIST" /> สำหรับโหมด <ph name="DEVICE_PRINTERS_ACCESS_MODE" /> เท่านั้น
@@ -786,6 +808,10 @@
           หากนโยบายนี้ได้รับการตั้งค่าเป็นเท็จหรือไม่ได้ตั้งค่า การจัดการพลังงานจะหน่วงเวลาและการจำกัดความยาวเซสชันจะเริ่มทำงานทันทีที่เริ่มเซสชัน</translation>
 <translation id="3478024346823118645">ล้างข้อมูลผู้ใช้เมื่อออกจากระบบ</translation>
 <translation id="348495353354674884">เปิดใช้งานแป้นพิมพ์เสมือน</translation>
+<translation id="3487623755010328395">
+        หากตั้งค่านโยบายนี้ <ph name="PRODUCT_NAME" /> จะพยายามลงทะเบียนตนเองและใช้นโยบายระบบคลาวด์ที่เกี่ยวข้องกับโปรไฟล์ทั้งหมด
+
+        ค่าของนโยบายนี้คือโทเค็นการลงทะเบียนที่ดึงได้จากคอนโซลผู้ดูแลระบบ Google</translation>
 <translation id="3496296378755072552">ตัวจัดการรหัสผ่าน</translation>
 <translation id="350443680860256679">กำหนดค่า ARC</translation>
 <translation id="3504791027627803580">ระบุ URL ของเครื่องมือค้นหาที่ใช้ในการให้การค้นหาภาพ คำขอค้นหาจะถูกส่งโดยใช้วิธีการ GET หากนโยบาย DefaultSearchProviderImageURLPostParams ถูกกำหนด คำขอค้นหาภาพจะใช้วิธีการ POST แทน
@@ -1338,6 +1364,17 @@
 
       หากไม่ได้ตั้งค่านโยบายนี้ไว้ หรือตั้งค่าเป็นสตริงว่างหรือช่วงพอร์ตที่ไม่ถูกต้อง จะเป็นการอนุญาตให้ WebRTC ใช้พอร์ต UDP ที่ว่างอยู่พอร์ตใดก็ได้ในเครื่อง</translation>
 <translation id="5290940294294002042">ระบุรายการปลั๊กอินที่ผู้ใช้สามารถเปิดหรือปิดใช้งาน</translation>
+<translation id="5301787427319106606">
+      หมายเหตุ: นโยบายนี้อยู่ในช่วงทดสอบและอาจส่งผลให้มีการทำงานผิดปกติ
+      คุณอาจต้องดูการตั้งค่านโยบาย IsolateOrigins เพื่อให้
+      ได้ผลลัพธ์ที่ดีที่สุดทั้งการแยกและการจำกัดผลกระทบที่มีต่อผู้ใช้ด้วยการใช้
+      IsolateOrigins กับรายการเว็บไซต์ที่คุณต้องการแยก
+      การตั้งค่า SitePerProcess นี้จะแยกเว็บไซต์ทั้งหมด
+      หากเปิดใช้นโยบาย แต่ละเว็บไซต์จะทำงานตามขั้นตอนของตนเอง
+      หากปิดใช้นโยบาย ระบบจะใช้ตรรกะการจัดการขั้นตอนการแยกแบบทีละเว็บไซต์
+      หากไม่ได้กำหนดค่านโยบายไว้ ผู้ใช้จะเปลี่ยนการตั้งค่านี้ได้
+      ใน <ph name="PRODUCT_OS_NAME" /> ขอแนะนำให้ตั้งค่านโยบายด้านอุปกรณ์ <ph name="DEVICE_LOGIN_SCREEN_SITE_PER_PROCESS_POLICY_NAME" /> เป็นค่าเดียวกันด้วย หากค่าที่นโยบายทั้งสองระบุไม่ตรงกัน อาจทำให้เกิดความล่าช้าเมื่อเข้าสู่เซสชันของผู้ใช้ในขณะที่นำค่าที่นโยบายด้านผู้ใช้ระบุไปใช้
+      </translation>
 <translation id="5302612588919538756">นโยบายนี้เลิกใช้งานแล้ว ลองพิจารณาใช้ SyncDisabled แทน
 
       อนุญาตให้ผู้ใช้ลงชื่อเข้าใช้ <ph name="PRODUCT_NAME" />
@@ -1894,6 +1931,14 @@
 <translation id="706669471845501145">อนุญาตให้ไซต์แสดงการแจ้งเตือนของเดสก์ท็อป</translation>
 <translation id="7072208053150563108">อัตราการเปลี่ยนรหัสผ่านโดยเครื่อง</translation>
 <translation id="7072406291414141328">เปิดใช้การควบคุมปริมาณแบนด์วิดท์ของเครือข่าย</translation>
+<translation id="7074513465313721551">กำหนดค่ารายการโดเมนที่ Safe Browsing จะเชื่อถือซึ่งหมายถึง
+      Safe Browsing จะไม่ตรวจสอบหาทรัพยากรที่เป็นอันตราย (เช่น ฟิชชิง มัลแวร์ หรือซอฟต์แวร์ไม่พึงประสงค์) หาก URL ของทรัพยากรตรงกับโดเมนเหล่านี้
+      บริการปกป้องการดาวน์โหลดของ Safe Browsing จะไม่ตรวจสอบการดาวน์โหลดที่โฮสต์ในโดเมนเหล่านี้
+      บริการปกป้องรหัสผ่านของ Safe Browsing จะไม่ตรวจสอบการใช้รหัสผ่านซ้ำหาก URL ของหน้าเว็บตรงกับโดเมนเหล่านี้
+
+      หากเปิดใช้การตั้งค่านี้ Safe Browsing จะเชื่อถือโดเมนเหล่านี้
+      หากไม่ได้กำหนดการตั้งค่านี้หรือปิดใช้ ก็จะมีการใช้การปกป้องด้วย Safe Browsing เริ่มต้นกับทรัพยากรทั้งหมด
+      นโยบายนี้ไม่มีในเครื่อง Windows ที่ไม่ได้เข้าร่วมโดเมน <ph name="MS_AD_NAME" /></translation>
 <translation id="7079519252486108041">ปิดกั้นป๊อปอัปบนไซต์เหล่านี้</translation>
 <translation id="7106631983877564505">เปิดใช้การล็อกเมื่ออุปกรณ์ของ <ph name="PRODUCT_OS_NAME" /> ไม่มีการใช้งานหรือถูกระงับใช้งาน
 
diff --git a/components/proxy_config/ios/proxy_service_factory.cc b/components/proxy_config/ios/proxy_service_factory.cc
index f8d1f1d..784c276 100644
--- a/components/proxy_config/ios/proxy_service_factory.cc
+++ b/components/proxy_config/ios/proxy_service_factory.cc
@@ -43,7 +43,7 @@
 
 // static
 std::unique_ptr<net::ProxyResolutionService>
-ProxyServiceFactory::CreateProxyService(
+ProxyServiceFactory::CreateProxyResolutionService(
     net::NetLog* net_log,
     net::URLRequestContext* context,
     net::NetworkDelegate* network_delegate,
diff --git a/components/proxy_config/ios/proxy_service_factory.h b/components/proxy_config/ios/proxy_service_factory.h
index 77e112e..4c5e64f3 100644
--- a/components/proxy_config/ios/proxy_service_factory.h
+++ b/components/proxy_config/ios/proxy_service_factory.h
@@ -37,8 +37,9 @@
   static std::unique_ptr<PrefProxyConfigTracker>
   CreatePrefProxyConfigTrackerOfLocalState(PrefService* local_state_prefs);
 
-  // Create a proxy service.
-  static std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+  // Create a proxy resolution service.
+  static std::unique_ptr<net::ProxyResolutionService>
+  CreateProxyResolutionService(
       net::NetLog* net_log,
       net::URLRequestContext* context,
       net::NetworkDelegate* network_delegate,
diff --git a/components/reading_list/core/reading_list_model_impl.cc b/components/reading_list/core/reading_list_model_impl.cc
index 33f1a46..28bcd421 100644
--- a/components/reading_list/core/reading_list_model_impl.cc
+++ b/components/reading_list/core/reading_list_model_impl.cc
@@ -16,12 +16,12 @@
 ReadingListModelImpl::ReadingListModelImpl(
     std::unique_ptr<ReadingListModelStorage> storage,
     PrefService* pref_service,
-    std::unique_ptr<base::Clock> clock)
+    base::Clock* clock)
     : entries_(std::make_unique<ReadingListEntries>()),
       unread_entry_count_(0),
       read_entry_count_(0),
       unseen_entry_count_(0),
-      clock_(std::move(clock)),
+      clock_(clock),
       pref_service_(pref_service),
       has_unseen_(false),
       loaded_(false),
@@ -30,7 +30,7 @@
   DCHECK(clock_);
   if (storage) {
     storage_layer_ = std::move(storage);
-    storage_layer_->SetReadingListModel(this, this, clock_.get());
+    storage_layer_->SetReadingListModel(this, this, clock_);
   } else {
     loaded_ = true;
   }
diff --git a/components/reading_list/core/reading_list_model_impl.h b/components/reading_list/core/reading_list_model_impl.h
index 9e91e1e..52bd3b88 100644
--- a/components/reading_list/core/reading_list_model_impl.h
+++ b/components/reading_list/core/reading_list_model_impl.h
@@ -34,7 +34,7 @@
   // |clock| will be used to timestamp all the operations.
   ReadingListModelImpl(std::unique_ptr<ReadingListModelStorage> storage_layer,
                        PrefService* pref_service,
-                       std::unique_ptr<base::Clock> clock_);
+                       base::Clock* clock_);
 
   ReadingListModelImpl();
 
@@ -141,8 +141,7 @@
   // Set the unseen flag to true.
   void SetUnseenFlag();
 
-  // |storage_layer_| depends on |clock_| so keep the order.
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
   std::unique_ptr<ReadingListModelStorage> storage_layer_;
   PrefService* pref_service_;
   bool has_unseen_;
diff --git a/components/reading_list/core/reading_list_model_unittest.cc b/components/reading_list/core/reading_list_model_unittest.cc
index 0f8597f..8f619c77 100644
--- a/components/reading_list/core/reading_list_model_unittest.cc
+++ b/components/reading_list/core/reading_list_model_unittest.cc
@@ -159,20 +159,15 @@
                              public testing::Test {
  public:
   ReadingListModelTest() : callback_called_(false) {
-    auto clock = std::make_unique<base::SimpleTestClock>();
-    clock_ = clock.get();
-    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr,
-                                                    std::move(clock));
+    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr, &clock_);
     ClearCounts();
     model_->AddObserver(this);
   }
   ~ReadingListModelTest() override {}
 
-  void SetStorage(std::unique_ptr<TestReadingListStorage> storage,
-                  std::unique_ptr<base::SimpleTestClock> clock) {
-    clock_ = clock.get();
+  void SetStorage(std::unique_ptr<TestReadingListStorage> storage) {
     model_ = std::make_unique<ReadingListModelImpl>(std::move(storage), nullptr,
-                                                    std::move(clock));
+                                                    &clock_);
     ClearCounts();
     model_->AddObserver(this);
   }
@@ -303,8 +298,7 @@
   bool callback_called_;
 
   std::unique_ptr<ReadingListModelImpl> model_;
-  // Owned by |model_|;
-  base::SimpleTestClock* clock_;
+  base::SimpleTestClock clock_;
 };
 
 // Tests creating an empty model.
@@ -324,10 +318,9 @@
 // Tests load model.
 TEST_F(ReadingListModelTest, ModelLoaded) {
   ClearCounts();
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
   storage->AddSampleEntries();
-  SetStorage(std::move(storage), std::move(clock));
+  SetStorage(std::move(storage));
 
   AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
   std::map<GURL, std::string> loaded_entries;
@@ -349,9 +342,8 @@
 
 // Tests adding entry.
 TEST_F(ReadingListModelTest, AddEntry) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   ClearCounts();
 
   const ReadingListEntry& entry =
@@ -376,9 +368,8 @@
 
 // Tests adding an entry that already exists.
 TEST_F(ReadingListModelTest, AddExistingEntry) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   GURL url = GURL("http://example.com");
   std::string title = "\n  \tsample Test ";
   model_->AddEntry(url, title, reading_list::ADDED_VIA_CURRENT_APP);
@@ -405,12 +396,11 @@
 
 // Tests addin entry from sync.
 TEST_F(ReadingListModelTest, SyncAddEntry) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   auto entry = std::make_unique<ReadingListEntry>(
-      GURL("http://example.com"), "sample", AdvanceAndGetTime(clock_));
-  entry->SetRead(true, AdvanceAndGetTime(clock_));
+      GURL("http://example.com"), "sample", AdvanceAndGetTime(&clock_));
+  entry->SetRead(true, AdvanceAndGetTime(&clock_));
   ClearCounts();
 
   model_->SyncAddEntry(std::move(entry));
@@ -423,9 +413,8 @@
 
 // Tests updating entry from sync.
 TEST_F(ReadingListModelTest, SyncMergeEntry) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   model_->AddEntry(GURL("http://example.com"), "sample",
                    reading_list::ADDED_VIA_CURRENT_APP);
   const base::FilePath distilled_path(FILE_PATH_LITERAL("distilled/page.html"));
@@ -440,8 +429,8 @@
   int64_t local_update_time = local_entry->UpdateTime();
 
   auto sync_entry = std::make_unique<ReadingListEntry>(
-      GURL("http://example.com"), "sample", AdvanceAndGetTime(clock_));
-  sync_entry->SetRead(true, AdvanceAndGetTime(clock_));
+      GURL("http://example.com"), "sample", AdvanceAndGetTime(&clock_));
+  sync_entry->SetRead(true, AdvanceAndGetTime(&clock_));
   ASSERT_GT(sync_entry->UpdateTime(), local_update_time);
   int64_t sync_update_time = sync_entry->UpdateTime();
   EXPECT_TRUE(sync_entry->DistilledPath().empty());
@@ -463,9 +452,8 @@
 
 // Tests deleting entry.
 TEST_F(ReadingListModelTest, RemoveEntryByUrl) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   model_->AddEntry(GURL("http://example.com"), "sample",
                    reading_list::ADDED_VIA_CURRENT_APP);
   ClearCounts();
@@ -496,9 +484,8 @@
 
 // Tests deleting entry from sync.
 TEST_F(ReadingListModelTest, RemoveSyncEntryByUrl) {
-  auto clock = std::make_unique<base::SimpleTestClock>();
-  auto storage = std::make_unique<TestReadingListStorage>(this, clock.get());
-  SetStorage(std::move(storage), std::move(clock));
+  auto storage = std::make_unique<TestReadingListStorage>(this, &clock_);
+  SetStorage(std::move(storage));
   model_->AddEntry(GURL("http://example.com"), "sample",
                    reading_list::ADDED_VIA_CURRENT_APP);
   ClearCounts();
diff --git a/components/reading_list/core/reading_list_store_unittest.cc b/components/reading_list/core/reading_list_store_unittest.cc
index 911f9e8..af55638e 100644
--- a/components/reading_list/core/reading_list_store_unittest.cc
+++ b/components/reading_list/core/reading_list_store_unittest.cc
@@ -95,11 +95,8 @@
         base::BindOnce(&syncer::ModelTypeStoreTestUtil::MoveStoreToCallback,
                        std::move(store_)),
         CreateModelTypeChangeProcessor());
-    auto clock = std::make_unique<base::SimpleTestClock>();
-    clock_ = clock.get();
-    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr,
-                                                    std::move(clock));
-    reading_list_store_->SetReadingListModel(model_.get(), this, clock_);
+    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr, &clock_);
+    reading_list_store_->SetReadingListModel(model_.get(), this, &clock_);
 
     base::RunLoop().RunUntilIdle();
   }
@@ -175,7 +172,7 @@
 
   std::unique_ptr<syncer::ModelTypeStore> store_;
   std::unique_ptr<ReadingListModelImpl> model_;
-  base::SimpleTestClock* clock_;
+  base::SimpleTestClock clock_;
   std::unique_ptr<ReadingListStore> reading_list_store_;
   int put_called_;
   int delete_called_;
@@ -195,9 +192,9 @@
 
 TEST_F(ReadingListStoreTest, SaveOneRead) {
   ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
-                         AdvanceAndGetTime(clock_));
-  entry.SetRead(true, AdvanceAndGetTime(clock_));
-  AdvanceAndGetTime(clock_);
+                         AdvanceAndGetTime(&clock_));
+  entry.SetRead(true, AdvanceAndGetTime(&clock_));
+  AdvanceAndGetTime(&clock_);
   reading_list_store_->SaveEntry(entry);
   AssertCounts(1, 0, 0, 0, 0);
   syncer::EntityData* data = put_multimap_["http://read.example.com/"].get();
@@ -210,7 +207,7 @@
 
 TEST_F(ReadingListStoreTest, SaveOneUnread) {
   ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title",
-                         AdvanceAndGetTime(clock_));
+                         AdvanceAndGetTime(&clock_));
   reading_list_store_->SaveEntry(entry);
   AssertCounts(1, 0, 0, 0, 0);
   syncer::EntityData* data = put_multimap_["http://unread.example.com/"].get();
@@ -224,8 +221,8 @@
 TEST_F(ReadingListStoreTest, SyncMergeOneEntry) {
   syncer::EntityChangeList remote_input;
   ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
-                         AdvanceAndGetTime(clock_));
-  entry.SetRead(true, AdvanceAndGetTime(clock_));
+                         AdvanceAndGetTime(&clock_));
+  entry.SetRead(true, AdvanceAndGetTime(&clock_));
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       entry.AsReadingListSpecifics();
 
@@ -248,8 +245,8 @@
 
 TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) {
   ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
-                         AdvanceAndGetTime(clock_));
-  entry.SetRead(true, AdvanceAndGetTime(clock_));
+                         AdvanceAndGetTime(&clock_));
+  entry.SetRead(true, AdvanceAndGetTime(&clock_));
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       entry.AsReadingListSpecifics();
   syncer::EntityData data;
@@ -269,13 +266,13 @@
 }
 
 TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) {
-  AdvanceAndGetTime(clock_);
+  AdvanceAndGetTime(&clock_);
   model_->AddEntry(GURL("http://unread.example.com/"), "unread title",
                    reading_list::ADDED_VIA_CURRENT_APP);
 
   ReadingListEntry new_entry(GURL("http://unread.example.com/"), "unread title",
-                             AdvanceAndGetTime(clock_));
-  new_entry.SetRead(true, AdvanceAndGetTime(clock_));
+                             AdvanceAndGetTime(&clock_));
+  new_entry.SetRead(true, AdvanceAndGetTime(&clock_));
   std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
       new_entry.AsReadingListSpecifics();
   syncer::EntityData data;
@@ -296,10 +293,10 @@
 TEST_F(ReadingListStoreTest, ApplySyncChangesOneIgnored) {
   // Read entry but with unread URL as it must update the other one.
   ReadingListEntry old_entry(GURL("http://unread.example.com/"),
-                             "old unread title", AdvanceAndGetTime(clock_));
-  old_entry.SetRead(true, AdvanceAndGetTime(clock_));
+                             "old unread title", AdvanceAndGetTime(&clock_));
+  old_entry.SetRead(true, AdvanceAndGetTime(&clock_));
 
-  AdvanceAndGetTime(clock_);
+  AdvanceAndGetTime(&clock_);
   model_->AddEntry(GURL("http://unread.example.com/"), "new unread title",
                    reading_list::ADDED_VIA_CURRENT_APP);
   AssertCounts(0, 0, 0, 0, 0);
diff --git a/components/sessions/core/base_session_service.cc b/components/sessions/core/base_session_service.cc
index 4d113ac..3e76628 100644
--- a/components/sessions/core/base_session_service.cc
+++ b/components/sessions/core/base_session_service.cc
@@ -133,7 +133,7 @@
   // opportunity to append more commands.
   delegate_->OnWillSaveCommands();
 
-  if (pending_commands_.empty() && !pending_reset_)
+  if (pending_commands_.empty())
     return;
 
   // We create a new vector which will receive all elements from the
diff --git a/components/sessions/core/persistent_tab_restore_service.cc b/components/sessions/core/persistent_tab_restore_service.cc
index 655130e..ba77aa9 100644
--- a/components/sessions/core/persistent_tab_restore_service.cc
+++ b/components/sessions/core/persistent_tab_restore_service.cc
@@ -534,7 +534,9 @@
 
   // Schedule a pending reset so that we nuke the file on next write.
   base_session_service_->set_pending_reset(true);
-  base_session_service_->StartSaveTimer();
+  // Schedule a command, otherwise if there are no pending commands Save does
+  // nothing.
+  base_session_service_->ScheduleCommand(CreateRestoredEntryCommand(1));
 }
 
 void PersistentTabRestoreService::Delegate::OnNavigationEntriesDeleted() {
@@ -543,7 +545,9 @@
 
   // Schedule a pending reset so that we nuke the file on next write.
   base_session_service_->set_pending_reset(true);
-  base_session_service_->StartSaveTimer();
+  // Schedule a command, otherwise if there are no pending commands Save does
+  // nothing.
+  base_session_service_->ScheduleCommand(CreateRestoredEntryCommand(1));
 }
 
 void PersistentTabRestoreService::Delegate::OnRestoreEntryById(
diff --git a/components/sessions/core/session_backend.cc b/components/sessions/core/session_backend.cc
index 0f276e1..07a807f9 100644
--- a/components/sessions/core/session_backend.cc
+++ b/components/sessions/core/session_backend.cc
@@ -231,8 +231,7 @@
       !AppendCommandsToFile(current_session_file_.get(), commands)) {
     current_session_file_.reset(nullptr);
   }
-  if (!commands.empty())
-    empty_file_ = false;
+  empty_file_ = false;
 }
 
 void SessionBackend::ReadLastSessionCommands(
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb
index 5d838a7..816a8dc 100644
--- a/components/strings/components_strings_gu.xtb
+++ b/components/strings/components_strings_gu.xtb
@@ -430,6 +430,7 @@
 <translation id="4103249731201008433">ઉપકરણ અનુક્ર્માંક નંબર અમાન્ય છે</translation>
 <translation id="410351446219883937">ઑટોપ્લે</translation>
 <translation id="4103763322291513355">બ્લેકલિસ્ટ કરેલા URL ની સૂચિ અને તમારા સિસ્ટમ વ્યવસ્થાપક દ્વારા લાગુ અન્ય નીતિઓ જોવા માટે &lt;strong&gt;chrome://policy&lt;/strong&gt; ની મુલાકાત લો.</translation>
+<translation id="4110652170750985508">તમારી ચુકવણીને રિવ્યૂ કરો</translation>
 <translation id="4116663294526079822">હંમેશા આ સાઇટ પર મંજૂરી આપો</translation>
 <translation id="4117700440116928470">નીતિ મર્યાદા સમર્થિત નથી.</translation>
 <translation id="4129401438321186435">{COUNT,plural, =1{1 અન્ય}one{# અન્ય}other{# અન્ય}}</translation>
diff --git a/components/strings/components_strings_iw.xtb b/components/strings/components_strings_iw.xtb
index 82a5581..40ec4ea 100644
--- a/components/strings/components_strings_iw.xtb
+++ b/components/strings/components_strings_iw.xtb
@@ -430,6 +430,7 @@
 <translation id="4103249731201008433">המספר הסידורי של המכשיר אינו חוקי</translation>
 <translation id="410351446219883937">הפעלה אוטומטית</translation>
 <translation id="4103763322291513355">‏היכנס לכתובת &lt;strong&gt;chrome://policy&lt;/strong&gt; כדי לראות רשימה של כתובות אתרים שנמנעה אליהם הגישה, כמו גם תקנונים אחרים שנאכפו על ידי מנהל המערכת שלך.</translation>
+<translation id="4110652170750985508">בדיקת התשלום</translation>
 <translation id="4116663294526079822">אפשר תמיד באתר זה</translation>
 <translation id="4117700440116928470">היקף המדיניות אינו נתמך.</translation>
 <translation id="4129401438321186435">{COUNT,plural, =1{אחד נוסף}two{שניים נוספים}many{# נוספים}other{# נוספים}}</translation>
diff --git a/components/strings/components_strings_th.xtb b/components/strings/components_strings_th.xtb
index e100d339..f7fbc24 100644
--- a/components/strings/components_strings_th.xtb
+++ b/components/strings/components_strings_th.xtb
@@ -430,6 +430,7 @@
 <translation id="4103249731201008433">หมายเลขซีเรียลของอุปกรณ์ไม่ถูกต้อง</translation>
 <translation id="410351446219883937">เล่นอัตโนมัติ</translation>
 <translation id="4103763322291513355">ไปที่ &lt;strong&gt;chrome://policy&lt;/strong&gt; เพื่อดูรายการของ URL ที่ไม่ได้รับอนุญาต และนโยบายอื่นๆ ที่ผู้ดูแลระบบของคุณบังคับใช้</translation>
+<translation id="4110652170750985508">ตรวจสอบการชำระเงิน</translation>
 <translation id="4116663294526079822">อนุญาตบนไซต์นี้เสมอ</translation>
 <translation id="4117700440116928470">ขอบข่ายนโยบายไม่ได้รับการสนับสนุน</translation>
 <translation id="4129401438321186435">{COUNT,plural, =1{อีก 1 รายการ}other{อีก # รายการ}}</translation>
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 74d4553..cb74471 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -783,6 +783,7 @@
   deps = [
     ":sync",
     ":test_support_engine",
+    "//components/signin/core/browser:account_info",
     "//components/sync_preferences:test_support",
     "//components/version_info",
     "//google_apis",
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index 1f2572e..0f51c157 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -12,7 +12,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "components/signin/core/browser/signin_manager_base.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
@@ -245,11 +244,8 @@
 std::unique_ptr<base::DictionaryValue> ConstructAboutInformation_DEPRECATED(
     SyncService* service,
     version_info::Channel channel) {
-  AccountInfo primary_account_info;
-  if (service->signin())
-    primary_account_info = service->signin()->GetAuthenticatedAccountInfo();
-
-  return ConstructAboutInformation(service, primary_account_info, channel);
+  return ConstructAboutInformation(
+      service, service->GetAuthenticatedAccountInfo(), channel);
 }
 
 // This function both defines the structure of the message to be returned and
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index b763434..f84f851 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -5,6 +5,7 @@
 #include "components/sync/driver/fake_sync_service.h"
 
 #include "base/values.h"
+#include "components/signin/core/browser/account_info.h"
 #include "components/sync/driver/data_type_controller.h"
 #include "components/sync/syncable/base_transaction.h"
 #include "components/sync/syncable/user_share.h"
@@ -204,8 +205,8 @@
 void FakeSyncService::GetAllNodes(
     const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {}
 
-SigninManagerBase* FakeSyncService::signin() const {
-  return nullptr;
+AccountInfo FakeSyncService::GetAuthenticatedAccountInfo() const {
+  return AccountInfo();
 }
 
 GlobalIdMapper* FakeSyncService::GetGlobalIdMapper() const {
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index adf1022..d06f73c 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -88,7 +88,7 @@
   base::WeakPtr<JsController> GetJsController() override;
   void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
                        callback) override;
-  SigninManagerBase* signin() const override;
+  AccountInfo GetAuthenticatedAccountInfo() const override;
   GlobalIdMapper* GetGlobalIdMapper() const override;
 
   // DataTypeEncryptionHandler implementation.
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index b03cc20..7be427e 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -20,8 +20,8 @@
 #include "components/sync/engine/connection_status.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
+struct AccountInfo;
 class GoogleServiceAuthError;
-class SigninManagerBase;
 
 namespace sync_sessions {
 class OpenTabsUIDelegate;
@@ -350,9 +350,8 @@
       const base::Callback<void(std::unique_ptr<base::ListValue>)>&
           callback) = 0;
 
-  // Non-owning pointer to sign in logic that can be used to fetch information
-  // about the currently signed in user.
-  virtual SigninManagerBase* signin() const = 0;
+  // Information about the currently signed in user.
+  virtual AccountInfo GetAuthenticatedAccountInfo() const = 0;
 
   virtual GlobalIdMapper* GetGlobalIdMapper() const = 0;
 
diff --git a/components/sync/driver/sync_service_base.cc b/components/sync/driver/sync_service_base.cc
index 3fc72d28..511e8fb 100644
--- a/components/sync/driver/sync_service_base.cc
+++ b/components/sync/driver/sync_service_base.cc
@@ -7,12 +7,13 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/syslog_logging.h"
 #include "components/invalidation/public/invalidation_service.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -82,9 +83,10 @@
   return observers_.HasObserver(observer);
 }
 
-SigninManagerBase* SyncServiceBase::signin() const {
+AccountInfo SyncServiceBase::GetAuthenticatedAccountInfo() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return signin_ ? signin_->GetOriginal() : nullptr;
+  return signin_ ? signin_->GetOriginal()->GetAuthenticatedAccountInfo()
+                 : AccountInfo();
 }
 
 // static
diff --git a/components/sync/driver/sync_service_base.h b/components/sync/driver/sync_service_base.h
index a012196..1f97abf4 100644
--- a/components/sync/driver/sync_service_base.h
+++ b/components/sync/driver/sync_service_base.h
@@ -47,7 +47,7 @@
   void AddObserver(SyncServiceObserver* observer) override;
   void RemoveObserver(SyncServiceObserver* observer) override;
   bool HasObserver(const SyncServiceObserver* observer) const override;
-  SigninManagerBase* signin() const override;
+  AccountInfo GetAuthenticatedAccountInfo() const override;
 
   // Given base path (path to profile) formats path to "Sync Data" folder where
   // sync engine stores directory database.
diff --git a/components/sync/engine_impl/model_type_worker.cc b/components/sync/engine_impl/model_type_worker.cc
index a38c0de2..5333687 100644
--- a/components/sync/engine_impl/model_type_worker.cc
+++ b/components/sync/engine_impl/model_type_worker.cc
@@ -151,7 +151,7 @@
     WorkerEntityTracker* entity =
         GetOrCreateEntityTracker(data.client_tag_hash);
 
-    if (!entity->UpdateContainsNewVersion(response_data)) {
+    if (!entity->UpdateContainsNewVersion(response_data.response_version)) {
       status->increment_num_reflected_updates_downloaded_by(1);
       ++counters->num_reflected_updates_received;
     }
@@ -176,7 +176,7 @@
     } else if (cryptographer_ &&
                cryptographer_->CanDecrypt(specifics.encrypted())) {
       // Encrypted and we know the key.
-      if (DecryptSpecifics(specifics, &data.specifics)) {
+      if (DecryptSpecifics(*cryptographer_, specifics, &data.specifics)) {
         response_data.entity = data.PassToPtr();
         response_data.encryption_key_name = specifics.encrypted().key_name();
         entity->ReceiveUpdate(response_data);
@@ -377,7 +377,8 @@
 
       if (cryptographer_->CanDecrypt(data.specifics.encrypted())) {
         EntityData decrypted_data;
-        if (DecryptSpecifics(data.specifics, &decrypted_data.specifics)) {
+        if (DecryptSpecifics(*cryptographer_, data.specifics,
+                             &decrypted_data.specifics)) {
           // Copy other fields one by one since EntityData doesn't allow
           // copying.
           decrypted_data.id = data.id;
@@ -402,13 +403,14 @@
   }
 }
 
-bool ModelTypeWorker::DecryptSpecifics(const sync_pb::EntitySpecifics& in,
+// static
+bool ModelTypeWorker::DecryptSpecifics(const Cryptographer& cryptographer,
+                                       const sync_pb::EntitySpecifics& in,
                                        sync_pb::EntitySpecifics* out) {
-  DCHECK(cryptographer_);
   DCHECK(in.has_encrypted());
-  DCHECK(cryptographer_->CanDecrypt(in.encrypted()));
+  DCHECK(cryptographer.CanDecrypt(in.encrypted()));
 
-  std::string plaintext = cryptographer_->DecryptToString(in.encrypted());
+  std::string plaintext = cryptographer.DecryptToString(in.encrypted());
   if (plaintext.empty()) {
     LOG(ERROR) << "Failed to decrypt a decryptable entity";
     return false;
diff --git a/components/sync/engine_impl/model_type_worker.h b/components/sync/engine_impl/model_type_worker.h
index 098fccb..f6d3a5cdd 100644
--- a/components/sync/engine_impl/model_type_worker.h
+++ b/components/sync/engine_impl/model_type_worker.h
@@ -115,6 +115,19 @@
  private:
   using EntityMap = std::map<std::string, std::unique_ptr<WorkerEntityTracker>>;
 
+  // Attempts to decrypt the given specifics and return them in the |out|
+  // parameter. Assumes cryptographer.CanDecrypt(specifics) returned true.
+  //
+  // Returns false if the decryption failed. There are no guarantees about the
+  // contents of |out| when that happens.
+  //
+  // In theory, this should never fail. Only corrupt or invalid entries could
+  // cause this to fail, and no clients are known to create such entries. The
+  // failure case is an attempt to be defensive against bad input.
+  static bool DecryptSpecifics(const Cryptographer& cryptographer,
+                               const sync_pb::EntitySpecifics& in,
+                               sync_pb::EntitySpecifics* out);
+
   // Helper function to actually send |pending_updates_| to the processor.
   void ApplyPendingUpdates();
 
@@ -143,18 +156,6 @@
   // Should only be called during a GetUpdates cycle.
   void DecryptStoredEntities();
 
-  // Attempts to decrypt the given specifics and return them in the |out|
-  // parameter. Assumes cryptographer_->CanDecrypt(specifics) returned true.
-  //
-  // Returns false if the decryption failed. There are no guarantees about the
-  // contents of |out| when that happens.
-  //
-  // In theory, this should never fail. Only corrupt or invalid entries could
-  // cause this to fail, and no clients are known to create such entries. The
-  // failure case is an attempt to be defensive against bad input.
-  bool DecryptSpecifics(const sync_pb::EntitySpecifics& in,
-                        sync_pb::EntitySpecifics* out);
-
   // Returns the entity tracker for the given |tag_hash|, or nullptr.
   WorkerEntityTracker* GetEntityTracker(const std::string& tag_hash);
 
diff --git a/components/sync/engine_impl/worker_entity_tracker.cc b/components/sync/engine_impl/worker_entity_tracker.cc
index 2d74b7d..b15ce16 100644
--- a/components/sync/engine_impl/worker_entity_tracker.cc
+++ b/components/sync/engine_impl/worker_entity_tracker.cc
@@ -22,7 +22,7 @@
 WorkerEntityTracker::~WorkerEntityTracker() {}
 
 void WorkerEntityTracker::ReceiveUpdate(const UpdateResponseData& update) {
-  if (!UpdateContainsNewVersion(update))
+  if (!UpdateContainsNewVersion(update.response_version))
     return;
 
   highest_gu_response_version_ = update.response_version;
@@ -34,9 +34,8 @@
   ClearEncryptedUpdate();
 }
 
-bool WorkerEntityTracker::UpdateContainsNewVersion(
-    const UpdateResponseData& update) {
-  return (update.response_version > highest_gu_response_version_);
+bool WorkerEntityTracker::UpdateContainsNewVersion(int64_t update_version) {
+  return update_version > highest_gu_response_version_;
 }
 
 bool WorkerEntityTracker::ReceiveEncryptedUpdate(
diff --git a/components/sync/engine_impl/worker_entity_tracker.h b/components/sync/engine_impl/worker_entity_tracker.h
index bf35382..7aa9f64 100644
--- a/components/sync/engine_impl/worker_entity_tracker.h
+++ b/components/sync/engine_impl/worker_entity_tracker.h
@@ -40,8 +40,8 @@
   // Handles receipt of an update from the server.
   void ReceiveUpdate(const UpdateResponseData& update);
 
-  // Check if update contains newer version than local.
-  bool UpdateContainsNewVersion(const UpdateResponseData& update);
+  // Check if |update_version| is newer than local.
+  bool UpdateContainsNewVersion(int64_t update_version);
 
   // Handles the receipt of an encrypted update from the server.
   //
diff --git a/components/translate/core/browser/translate_ranker_impl.cc b/components/translate/core/browser/translate_ranker_impl.cc
index 7066053..aa5abc4 100644
--- a/components/translate/core/browser/translate_ranker_impl.cc
+++ b/components/translate/core/browser/translate_ranker_impl.cc
@@ -79,6 +79,10 @@
 const char kDefaultTranslateRankerModelURL[] =
     "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/"
     "translate/android/translate_ranker_model_android_20170918.pb.bin";
+#elif defined(USE_AURA)
+const char kDefaultTranslateRankerModelURL[] =
+    "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/"
+    "translate/translate_ranker_20180123.model";
 #else
 const char kDefaultTranslateRankerModelURL[] =
     "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/"
@@ -91,7 +95,7 @@
     "TranslateRankerEnforcement", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kTranslateRankerAutoBlacklistOverride{
-    "TranslateRankerAutoBlacklistOverride", base::FEATURE_DISABLED_BY_DEFAULT};
+    "TranslateRankerAutoBlacklistOverride", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kTranslateRankerPreviousLanguageMatchesOverride{
     "TranslateRankerPreviousLanguageMatchesOverride",
diff --git a/components/update_client/request_sender.cc b/components/update_client/request_sender.cc
index a008284..190cf58 100644
--- a/components/update_client/request_sender.cc
+++ b/components/update_client/request_sender.cc
@@ -25,10 +25,10 @@
 namespace {
 
 // This is an ECDSA prime256v1 named-curve key.
-constexpr int kKeyVersion = 7;
+constexpr int kKeyVersion = 8;
 const char kKeyPubBytesBase64[] =
-    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj0QKufXIOBN30DtKeOYA5NV64FfY"
-    "HDou4sGqtcNUIlxpTzIbO45rB45QILhW6aDTwwjWLR1YCqpEAGICvFs8dQ==";
+    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+J2iCpfk8lThcuKUPzTaVcUjhNR3"
+    "AYHK+tTelGdHvyGGx7RP7BphYSPmpH6P4Vr72ak0W1a0bW55O9HW2oz3rQ==";
 
 // The ETag header carries the ECSDA signature of the protocol response, if
 // signing has been used.
diff --git a/components/variations/proto/study.proto b/components/variations/proto/study.proto
index 2ed59b7..3252414b 100644
--- a/components/variations/proto/study.proto
+++ b/components/variations/proto/study.proto
@@ -194,13 +194,13 @@
 
   // Possible form factors Chrome is running on.
   enum FormFactor {
-    // Chrome Desktop on Windows, Mac, Linux, or ChromeOS.
+    // Chrome Desktop on Windows, Mac, Linux, or Chrome OS.
     DESKTOP = 0;
     // Phone-based mobile Chrome, e.g. an Android phone or iPhone.
     PHONE   = 1;
     // Tablet-based mobile Chrome, e.g. an Android tablet or iPad.
     TABLET  = 2;
-    // ChromeOS running in single-app Kiosk mode.
+    // Chrome OS running in single-app Kiosk mode.
     KIOSK   = 3;
   }
 
@@ -271,22 +271,35 @@
     // Takes the same range of values as form_factor, e.g. [PHONE, TABLET].
     repeated FormFactor exclude_form_factor = 14;
 
-    // List of ChromeOS hardware classes that will receive this study. Each
-    // entry is treated as a substring of the actual device hardware_class,
-    // so "FOO" will match the client's hardware class "Device FOOBAR". If
-    // omitted, the study applies to all hardware classes unless
+    // List of Chrome OS hardware classes that will receive this study.
+    //
+    // Starting with Chrome M67, this does a case insensitive match on the same
+    // hardware class field that is reported to UMA in the SystemProfileProto's
+    // |hardware.hardware_class| field.
+    //
+    // Older versions did a case sensitive substring comparison, which was
+    // problematic for short hardware classes like "eve" that existed as
+    // substrings of other longer ones.
+    //
+    // If omitted, the study applies to all hardware classes unless
     // |exclude_hardware_class| is specified. Mutually exclusive with
     // |exclude_hardware_class|.
-    // An example might be "lumpy", "daisy", etc.
+    // Ex: ["veyron_minnie", "daisy"]
     repeated string hardware_class = 8;
 
-    // List of ChromeOS hardware classes that will be excluded in this
-    // study. Each entry is treated as a substring of the actual device
-    // hardware_class, so "FOO" will match the client's hardware class
-    // "Device FOOBAR". If omitted, the study applies to all hardware classes
-    // unless |hardware_class| is specified. Mutually exclusive with
-    // |hardware_class|.
-    // An example might be "lumpy", "daisy", etc.
+    // List of Chrome OS hardware classes that will be excluded in this study.
+    //
+    // Starting with Chrome M67, this does a case insensitive match on the same
+    // hardware class field that is reported to UMA in the SystemProfileProto's
+    // |hardware.hardware_class| field.
+    //
+    // Older versions did a case sensitive substring comparison, which was
+    // problematic for short hardware classes like "eve" that existed as
+    // substrings of other longer ones.
+    //
+    // If omitted, the study applies to all hardware classes unless
+    // |hardware_class| is specified. Mutually exclusive with |hardware_class|.
+    // Ex: ["veyron_minnie", "daisy"]
     repeated string exclude_hardware_class = 9;
 
     // List of lowercase ISO 3166-1 alpha-2 country codes that will receive this
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 7453986..840558a 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -275,7 +275,7 @@
       video_resource_updater->CreateExternalResourcesFromVideoFrame(
           video_frame);
 
-  EXPECT_EQ(cc::VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  EXPECT_EQ(cc::VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
             resources.resources.size());
   EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
@@ -379,7 +379,7 @@
       video_resource_updater->CreateExternalResourcesFromVideoFrame(
           video_frame);
 
-  EXPECT_EQ(cc::VideoFrameExternalResources::RGBA_RESOURCE, resources.type);
+  EXPECT_EQ(cc::VideoFrameResourceType::RGBA, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
   EXPECT_EQ(1u, resources.release_callbacks.size());
 
diff --git a/components/zucchini/image_utils.h b/components/zucchini/image_utils.h
index c3db9ed..0374ab7 100644
--- a/components/zucchini/image_utils.h
+++ b/components/zucchini/image_utils.h
@@ -20,7 +20,8 @@
 using offset_t = uint32_t;
 // Divide by 2 since label marking uses the most significant bit.
 constexpr offset_t kOffsetBound = static_cast<offset_t>(-1) / 2;
-constexpr offset_t kInvalidOffset = static_cast<offset_t>(-1);
+// Use 0xFFFFFFF*E*, since 0xFFFFFFF*F* is a sentinel value for Dex references.
+constexpr offset_t kInvalidOffset = static_cast<offset_t>(-2);
 
 // key_t is used to identify an offset in a table.
 using key_t = uint32_t;
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 5a735d85..1d7b9719 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -618,14 +618,22 @@
   bool would_exceed_quota_;
   int64_t space_available_;
   int64_t new_origin_usage_;
+  int64_t max_appcache_origin_cache_size_;
   std::vector<int64_t> newly_deletable_response_ids_;
 };
 
 AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask(
-    AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache)
-    : StoreOrLoadTask(storage), group_(group), cache_(newest_cache),
-      success_(false), would_exceed_quota_(false),
-      space_available_(-1), new_origin_usage_(-1) {
+    AppCacheStorageImpl* storage,
+    AppCacheGroup* group,
+    AppCache* newest_cache)
+    : StoreOrLoadTask(storage),
+      group_(group),
+      cache_(newest_cache),
+      success_(false),
+      would_exceed_quota_(false),
+      space_available_(-1),
+      new_origin_usage_(-1),
+      max_appcache_origin_cache_size_(kDefaultQuota) {
   group_record_.group_id = group->group_id();
   group_record_.manifest_url = group->manifest_url();
   group_record_.origin = url::Origin::Create(group_record_.manifest_url);
@@ -639,6 +647,15 @@
       &intercept_namespace_records_,
       &fallback_namespace_records_,
       &online_whitelist_records_);
+
+  base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kMaxAppCacheOriginCacheSizeMb)) {
+    if (base::StringToInt64(command_line.GetSwitchValueASCII(
+                                switches::kMaxAppCacheOriginCacheSizeMb),
+                            &max_appcache_origin_cache_size_)) {
+      max_appcache_origin_cache_size_ *= kMB;
+    }
+  }
 }
 
 void AppCacheStorageImpl::StoreGroupAndCacheTask::GetQuotaThenSchedule() {
@@ -760,9 +777,10 @@
     return;
   }
 
-  // Use a simple hard-coded value when not using quota management.
+  // Use a user defined value or a simple hard-coded value when not using quota
+  // management.
   if (space_available_ == -1) {
-    if (new_origin_usage_ > kDefaultQuota) {
+    if (new_origin_usage_ > max_appcache_origin_cache_size_) {
       would_exceed_quota_ = true;
       success_ = false;
       return;
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index db0a890..a59273f 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -176,11 +176,10 @@
   // Called by either the appcache or network loader, whichever is in use.
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     // Don't MaybeFallback for appcache produced responses.
     if (appcache_loader_ || !handler_) {
-      remote_client_->OnReceiveResponse(response_head, ssl_info,
+      remote_client_->OnReceiveResponse(response_head,
                                         std::move(downloaded_file));
       return;
     }
@@ -189,19 +188,18 @@
     handler_->MaybeFallbackForSubresourceResponse(
         response_head,
         base::BindOnce(&SubresourceLoader::ContinueOnReceiveResponse,
-                       weak_factory_.GetWeakPtr(), response_head, ssl_info,
+                       weak_factory_.GetWeakPtr(), response_head,
                        std::move(downloaded_file)));
   }
 
   void ContinueOnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file,
       SingleRequestURLLoaderFactory::RequestHandler handler) {
     if (handler) {
       CreateAndStartAppCacheLoader(std::move(handler));
     } else {
-      remote_client_->OnReceiveResponse(response_head, ssl_info,
+      remote_client_->OnReceiveResponse(response_head,
                                         std::move(downloaded_file));
     }
   }
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index 6fe4e36..c02b0f1 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -624,7 +624,7 @@
     response.headers = info.headers;
     response.headers->GetMimeType(&response.mime_type);
 
-    client->OnReceiveResponse(response, base::nullopt, nullptr);
+    client->OnReceiveResponse(response, nullptr);
 
     mojo::DataPipe data_pipe;
 
diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc
index 26b10c17..321e4fa 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.cc
+++ b/content/browser/appcache/appcache_update_url_loader_request.cc
@@ -95,7 +95,6 @@
 
 void AppCacheUpdateJob::UpdateURLLoaderRequest::OnReceiveResponse(
     const network::ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   response_ = response_head;
 
@@ -104,8 +103,8 @@
   // have a helper function which populates the HttpResponseInfo structure from
   // the ResourceResponseHead structure.
   http_response_info_.reset(new net::HttpResponseInfo());
-  if (ssl_info.has_value())
-    http_response_info_->ssl_info = *ssl_info;
+  if (response_head.ssl_info.has_value())
+    http_response_info_->ssl_info = *response_head.ssl_info;
   http_response_info_->headers = response_head.headers;
   http_response_info_->was_fetched_via_spdy =
       response_head.was_fetched_via_spdy;
diff --git a/content/browser/appcache/appcache_update_url_loader_request.h b/content/browser/appcache/appcache_update_url_loader_request.h
index 5f36946b..e7279f6 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.h
+++ b/content/browser/appcache/appcache_update_url_loader_request.h
@@ -55,7 +55,6 @@
   // These methods are called by the network loader.
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index 42b1921..520195a 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -282,9 +282,11 @@
   response_head.was_fetched_via_spdy = http_info->was_fetched_via_spdy;
   response_head.was_alpn_negotiated = http_info->was_alpn_negotiated;
   response_head.alpn_negotiated_protocol = http_info->alpn_negotiated_protocol;
+  if (http_info->ssl_info.cert)
+    response_head.ssl_info = http_info->ssl_info;
   response_head.load_timing = load_timing_info_;
 
-  client_->OnReceiveResponse(response_head, http_info->ssl_info,
+  client_->OnReceiveResponse(response_head,
                              network::mojom::DownloadedTempFilePtr());
   client_->OnStartLoadingResponseBody(std::move(data_pipe_.consumer_handle));
 }
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index a8f0d121..0653c25 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -114,6 +114,13 @@
                      std::move(callback)));
 }
 
+void BackgroundFetchContext::GetIconDisplaySize(
+    blink::mojom::BackgroundFetchService::GetIconDisplaySizeCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  delegate_proxy_.GetIconDisplaySize(std::move(callback));
+}
+
 void BackgroundFetchContext::DidCreateRegistration(
     const BackgroundFetchRegistrationId& registration_id,
     const BackgroundFetchOptions& options,
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index 449de8af..0192e53 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -74,6 +74,11 @@
                   const SkBitmap& icon,
                   blink::mojom::BackgroundFetchService::FetchCallback callback);
 
+  // Gets display size for the icon for Background Fetch UI.
+  void GetIconDisplaySize(
+      blink::mojom::BackgroundFetchService::GetIconDisplaySizeCallback
+          callback);
+
   // Aborts the Background Fetch for the |registration_id|. The callback will be
   // invoked with INVALID_ID if the registration has already completed or
   // aborted, STORAGE_ERROR if an I/O error occurs, or NONE for success.
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index af57f4ef..9a2a3936f 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -10,7 +10,6 @@
 #include "components/download/public/common/download_item.h"
 #include "components/download/public/common/download_url_parameters.h"
 #include "content/browser/background_fetch/background_fetch_job_controller.h"
-#include "content/public/browser/background_fetch_delegate.h"
 #include "content/public/browser/background_fetch_response.h"
 #include "content/public/browser/download_manager.h"
 
@@ -41,6 +40,29 @@
     return weak_ptr_factory_.GetWeakPtr();
   }
 
+  void ForwardGetIconDisplaySizeCallbackToIO(
+      BackgroundFetchDelegate::GetIconDisplaySizeCallback callback,
+      const gfx::Size& display_size) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                            base::BindOnce(std::move(callback), display_size));
+  }
+
+  void GetIconDisplaySize(
+      BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    if (delegate_) {
+      delegate_->GetIconDisplaySize(
+          base::BindOnce(&Core::ForwardGetIconDisplaySizeCallbackToIO,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+    } else {
+      BrowserThread::PostTask(
+          BrowserThread::IO, FROM_HERE,
+          base::BindOnce(std::move(callback), gfx::Size(0, 0)));
+    }
+  }
+
   void CreateDownloadJob(const std::string& job_unique_id,
                          const std::string& title,
                          const url::Origin& origin,
@@ -230,6 +252,14 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
+void BackgroundFetchDelegateProxy::GetIconDisplaySize(
+    BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::BindOnce(&Core::GetIconDisplaySize,
+                                         ui_core_ptr_, std::move(callback)));
+}
+
 void BackgroundFetchDelegateProxy::CreateDownloadJob(
     const std::string& job_unique_id,
     const std::string& title,
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
index 7e935a47..f426328 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -15,8 +15,10 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/background_fetch/background_fetch_request_info.h"
+#include "content/public/browser/background_fetch_delegate.h"
 #include "content/public/browser/background_fetch_response.h"
 #include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/modules/background_fetch/background_fetch.mojom.h"
 
 class SkBitmap;
 
@@ -56,6 +58,10 @@
 
   ~BackgroundFetchDelegateProxy();
 
+  // Gets size of the icon to display with the Background Fetch UI.
+  void GetIconDisplaySize(
+      BackgroundFetchDelegate::GetIconDisplaySizeCallback callback);
+
   // Creates a new download grouping identified by |job_unique_id|. Further
   // downloads started by StartRequest will also use this |job_unique_id| so
   // that a notification can be updated with the current status. If the download
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 2590c678..59267f3 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -27,6 +27,8 @@
   FakeBackgroundFetchDelegate() {}
 
   // BackgroundFetchDelegate implementation:
+  void GetIconDisplaySize(
+      BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override {}
   void CreateDownloadJob(
       const std::string& job_unique_id,
       const std::string& title,
diff --git a/content/browser/background_fetch/background_fetch_service_impl.cc b/content/browser/background_fetch/background_fetch_service_impl.cc
index a1897c9..f7dd340 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -100,6 +100,12 @@
                                         icon, std::move(callback));
 }
 
+void BackgroundFetchServiceImpl::GetIconDisplaySize(
+    blink::mojom::BackgroundFetchService::GetIconDisplaySizeCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  background_fetch_context_->GetIconDisplaySize(std::move(callback));
+}
+
 void BackgroundFetchServiceImpl::UpdateUI(const std::string& unique_id,
                                           const std::string& title,
                                           UpdateUICallback callback) {
diff --git a/content/browser/background_fetch/background_fetch_service_impl.h b/content/browser/background_fetch/background_fetch_service_impl.h
index 8960f457..b38694df 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.h
+++ b/content/browser/background_fetch/background_fetch_service_impl.h
@@ -42,6 +42,7 @@
              const BackgroundFetchOptions& options,
              const SkBitmap& icon,
              FetchCallback callback) override;
+  void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
   void UpdateUI(const std::string& unique_id,
                 const std::string& title,
                 UpdateUICallback callback) override;
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc
index 950dda4..7e554491 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -55,6 +55,8 @@
 
 MockBackgroundFetchDelegate::~MockBackgroundFetchDelegate() {}
 
+void MockBackgroundFetchDelegate::GetIconDisplaySize(
+    BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) {}
 void MockBackgroundFetchDelegate::CreateDownloadJob(
     const std::string& job_unique_id,
     const std::string& title,
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.h b/content/browser/background_fetch/mock_background_fetch_delegate.h
index fc85aa8..fe63a87 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.h
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.h
@@ -63,6 +63,8 @@
   ~MockBackgroundFetchDelegate() override;
 
   // BackgroundFetchDelegate implementation:
+  void GetIconDisplaySize(
+      BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override;
   void CreateDownloadJob(
       const std::string& job_unique_id,
       const std::string& title,
diff --git a/content/browser/blob_storage/blob_internals_url_loader.cc b/content/browser/blob_storage/blob_internals_url_loader.cc
index 3068afd..f41b5cd 100644
--- a/content/browser/blob_storage/blob_internals_url_loader.cc
+++ b/content/browser/blob_storage/blob_internals_url_loader.cc
@@ -22,7 +22,7 @@
 
   network::mojom::URLLoaderClientPtr client;
   client.Bind(std::move(client_info));
-  client->OnReceiveResponse(resource_response, base::nullopt, nullptr);
+  client->OnReceiveResponse(resource_response, nullptr);
 
   std::string output = storage::ViewBlobInternalsJob::GenerateHTML(
       blob_storage_context->context());
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 70d6ebd..fe17f4a 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -15,6 +15,7 @@
 #include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/debug/alias.h"
 #include "base/deferred_sequenced_task_runner.h"
 #include "base/feature_list.h"
 #include "base/location.h"
@@ -37,6 +38,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/system_monitor/system_monitor.h"
 #include "base/task_scheduler/initialization_util.h"
+#include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -54,6 +56,7 @@
 #include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "content/browser/browser_process_sub_thread.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/compositor/gpu_process_transport_factory.h"
@@ -369,10 +372,11 @@
 MSVC_DISABLE_OPTIMIZE()
 MSVC_PUSH_DISABLE_WARNING(4748)
 
-NOINLINE void ResetThread_IO(std::unique_ptr<BrowserProcessSubThread> thread) {
-  volatile int inhibit_comdat = __LINE__;
-  ALLOW_UNUSED_LOCAL(inhibit_comdat);
-  thread.reset();
+NOINLINE void ResetThread_IO(
+    std::unique_ptr<BrowserProcessSubThread> io_thread) {
+  const int line_number = __LINE__;
+  io_thread.reset();
+  base::debug::Alias(&line_number);
 }
 
 MSVC_POP_WARNING()
@@ -994,11 +998,13 @@
         *task_scheduler_init_params.get());
   }
 
-  // |io_thread_| is created by |PostMainMessageLoopStart()|, but its
-  // full initialization is deferred until this point because it requires
-  // several dependencies we don't want to depend on so early in startup.
+  // The thread used for BrowserThread::IO is created in
+  // |PostMainMessageLoopStart()|, but it's only tagged as BrowserThread::IO
+  // here in order to prevent any code from statically posting to it before
+  // CreateThreads() (as such maintaining the invariant that PreCreateThreads()
+  // et al. "happen-before" BrowserThread::IO is "brought up").
   DCHECK(io_thread_);
-  io_thread_->InitIOThreadDelegate();
+  io_thread_->RegisterAsBrowserThread();
 
   created_threads_ = true;
   return result_code_;
@@ -1236,9 +1242,12 @@
   TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
   base::PlatformThread::SetName("CrBrowserMain");
 
-  // Register the main thread by instantiating it, but don't call any methods.
-  main_thread_.reset(
-      new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current()));
+  // Register the main thread. The main thread's task runner should already have
+  // been initialized in MainMessageLoopStart() (or before if
+  // MessageLoop::current() was externally provided).
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+  main_thread_.reset(new BrowserThreadImpl(
+      BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()));
 }
 
 int BrowserMainLoop::BrowserThreadsStarted() {
@@ -1410,7 +1419,7 @@
         "startup",
         "BrowserMainLoop::BrowserThreadsStarted::InitUserInputMonitor");
     user_input_monitor_ = media::UserInputMonitor::Create(
-        io_thread_->task_runner(), main_thread_->task_runner());
+        io_thread_->task_runner(), base::ThreadTaskRunnerHandle::Get());
   }
 
   {
@@ -1560,9 +1569,10 @@
   options.priority = base::ThreadPriority::DISPLAY;
 #endif
 
-  io_thread_.reset(new BrowserProcessSubThread(BrowserThread::IO));
+  io_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::IO);
+
   if (!io_thread_->StartWithOptions(options))
-    LOG(FATAL) << "Failed to start the browser thread: IO";
+    LOG(FATAL) << "Failed to start BrowserThread::IO";
 }
 
 void BrowserMainLoop::InitializeMojo() {
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index c5311b7..20b2ac7 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -13,7 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
-#include "content/browser/browser_process_sub_thread.h"
 #include "content/public/browser/browser_main_runner.h"
 #include "media/media_buildflags.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -92,6 +91,7 @@
 namespace content {
 class BrowserMainParts;
 class BrowserOnlineStateObserver;
+class BrowserProcessSubThread;
 class BrowserThreadImpl;
 class LoaderDelegateImpl;
 class MediaStreamManager;
@@ -243,7 +243,10 @@
 
   void MainMessageLoopRun();
 
+  // Initializes |io_thread_|. It will not be promoted to BrowserThread::IO
+  // until CreateThreads().
   void InitializeIOThread();
+
   void InitializeMojo();
   base::FilePath GetStartupTraceFileName(
       const base::CommandLine& command_line) const;
@@ -285,6 +288,7 @@
   std::unique_ptr<base::MessageLoop> main_message_loop_;
 
   // Members initialized in |PostMainMessageLoopStart()| -----------------------
+  std::unique_ptr<BrowserProcessSubThread> io_thread_;
   std::unique_ptr<base::SystemMonitor> system_monitor_;
   std::unique_ptr<base::PowerMonitor> power_monitor_;
   std::unique_ptr<base::HighResolutionTimerManager> hi_res_timer_manager_;
@@ -335,9 +339,6 @@
       gpu_data_manager_visual_proxy_;
 #endif
 
-  // Members initialized in |CreateThreads()| ----------------------------------
-  std::unique_ptr<BrowserProcessSubThread> io_thread_;
-
   // Members initialized in |BrowserThreadsStarted()| --------------------------
   std::unique_ptr<ServiceManagerContext> service_manager_context_;
   std::unique_ptr<mojo::edk::ScopedIPCSupport> mojo_ipc_support_;
diff --git a/content/browser/browser_main_loop_unittest.cc b/content/browser/browser_main_loop_unittest.cc
index 61ec07ae..728331b 100644
--- a/content/browser/browser_main_loop_unittest.cc
+++ b/content/browser/browser_main_loop_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/sys_info.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/test/scoped_command_line.h"
+#include "content/browser/browser_thread_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc
index febe54e5..20d32d3 100644
--- a/content/browser/browser_main_runner.cc
+++ b/content/browser/browser_main_runner.cc
@@ -16,6 +16,7 @@
 #include "base/run_loop.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/synchronization/atomic_flag.h"
 #include "base/time/time.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/trace_event.h"
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc
index 71f1396..b9ba0dc 100644
--- a/content/browser/browser_process_sub_thread.cc
+++ b/content/browser/browser_process_sub_thread.cc
@@ -4,66 +4,166 @@
 
 #include "content/browser/browser_process_sub_thread.h"
 
-#include "base/debug/leak_tracker.h"
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/memory_dump_manager.h"
-#include "build/build_config.h"
 #include "content/browser/browser_child_process_host_impl.h"
+#include "content/browser/browser_thread_impl.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/notification_service_impl.h"
+#include "content/public/browser/browser_thread_delegate.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif
+
 #if defined(OS_WIN)
 #include "base/win/scoped_com_initializer.h"
 #endif
 
 namespace content {
 
-BrowserProcessSubThread::BrowserProcessSubThread(BrowserThread::ID identifier)
-    : BrowserThreadImpl(identifier) {}
+namespace {
+BrowserThreadDelegate* g_io_thread_delegate = nullptr;
+}  // namespace
 
-BrowserProcessSubThread::BrowserProcessSubThread(
-    BrowserThread::ID identifier,
-    base::MessageLoop* message_loop)
-    : BrowserThreadImpl(identifier, message_loop) {}
+// static
+void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) {
+  // |delegate| can only be set/unset while BrowserThread::IO isn't up.
+  DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO));
+  // and it cannot be set twice.
+  DCHECK(!g_io_thread_delegate || !delegate);
+
+  g_io_thread_delegate = delegate;
+}
+
+BrowserProcessSubThread::BrowserProcessSubThread(BrowserThread::ID identifier)
+    : base::Thread(BrowserThreadImpl::GetThreadName(identifier)),
+      identifier_(identifier) {
+  // Not bound to creation thread.
+  DETACH_FROM_THREAD(browser_thread_checker_);
+}
 
 BrowserProcessSubThread::~BrowserProcessSubThread() {
   Stop();
 }
 
+void BrowserProcessSubThread::RegisterAsBrowserThread() {
+  DCHECK(IsRunning());
+
+  DCHECK(!browser_thread_);
+  browser_thread_.reset(new BrowserThreadImpl(identifier_, task_runner()));
+
+  // Unretained(this) is safe as |this| outlives its underlying thread.
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &BrowserProcessSubThread::CompleteInitializationOnBrowserThread,
+          Unretained(this)));
+}
+
+void BrowserProcessSubThread::AllowBlockingForTesting() {
+  DCHECK(!IsRunning());
+  is_blocking_allowed_for_testing_ = true;
+}
+
 void BrowserProcessSubThread::Init() {
+  DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
+
 #if defined(OS_WIN)
-  com_initializer_.reset(new base::win::ScopedCOMInitializer());
+  com_initializer_ = std::make_unique<base::win::ScopedCOMInitializer>();
 #endif
 
-  notification_service_.reset(new NotificationServiceImpl());
+  if (!is_blocking_allowed_for_testing_) {
+    base::DisallowBlocking();
+    base::DisallowBaseSyncPrimitives();
+  }
+}
 
-  BrowserThreadImpl::Init();
+void BrowserProcessSubThread::Run(base::RunLoop* run_loop) {
+  DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
 
-  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    // Though this thread is called the "IO" thread, it actually just routes
-    // messages around; it shouldn't be allowed to perform any blocking disk
-    // I/O.
-    base::ThreadRestrictions::SetIOAllowed(false);
-    base::ThreadRestrictions::DisallowWaiting();
+#if defined(OS_ANDROID)
+  // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
+  // Though it may create unnecessary VM thread objects, keeping thread name
+  // gives more benefit in debugging in the platform.
+  if (!thread_name().empty()) {
+    base::android::AttachCurrentThreadWithName(thread_name());
+  }
+#endif
+
+  switch (identifier_) {
+    case BrowserThread::UI:
+      // The main thread is usually promoted as the UI thread and doesn't go
+      // through Run() but some tests do run a separate UI thread.
+      UIThreadRun(run_loop);
+      break;
+    case BrowserThread::IO:
+      IOThreadRun(run_loop);
+      return;
+    case BrowserThread::ID_COUNT:
+      NOTREACHED();
+      break;
   }
 }
 
 void BrowserProcessSubThread::CleanUp() {
-  if (BrowserThread::CurrentlyOn(BrowserThread::IO))
-    IOThreadPreCleanUp();
+  DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
 
-  BrowserThreadImpl::CleanUp();
+  // Run extra cleanup if this thread represents BrowserThread::IO.
+  if (BrowserThread::CurrentlyOn(BrowserThread::IO))
+    IOThreadCleanUp();
+
+  if (identifier_ == BrowserThread::IO && g_io_thread_delegate)
+    g_io_thread_delegate->CleanUp();
 
   notification_service_.reset();
 
 #if defined(OS_WIN)
   com_initializer_.reset();
 #endif
+
+  browser_thread_.reset();
 }
 
-void BrowserProcessSubThread::IOThreadPreCleanUp() {
+void BrowserProcessSubThread::CompleteInitializationOnBrowserThread() {
+  DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
+
+  notification_service_ = std::make_unique<NotificationServiceImpl>();
+
+  if (identifier_ == BrowserThread::IO && g_io_thread_delegate) {
+    // Allow blocking calls while initializing the IO thread.
+    base::ScopedAllowBlocking allow_blocking_for_init;
+    g_io_thread_delegate->Init();
+  }
+}
+
+// We disable optimizations for Run specifications so the compiler doesn't merge
+// them all together.
+MSVC_DISABLE_OPTIMIZE()
+MSVC_PUSH_DISABLE_WARNING(4748)
+
+void BrowserProcessSubThread::UIThreadRun(base::RunLoop* run_loop) {
+  const int line_number = __LINE__;
+  Thread::Run(run_loop);
+  base::debug::Alias(&line_number);
+}
+
+void BrowserProcessSubThread::IOThreadRun(base::RunLoop* run_loop) {
+  const int line_number = __LINE__;
+  Thread::Run(run_loop);
+  base::debug::Alias(&line_number);
+}
+
+MSVC_POP_WARNING()
+MSVC_ENABLE_OPTIMIZE();
+
+void BrowserProcessSubThread::IOThreadCleanUp() {
+  DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
+
   // Kill all things that might be holding onto
   // net::URLRequest/net::URLRequestContexts.
 
diff --git a/content/browser/browser_process_sub_thread.h b/content/browser/browser_process_sub_thread.h
index 8122cdb..f4b8799 100644
--- a/content/browser/browser_process_sub_thread.h
+++ b/content/browser/browser_process_sub_thread.h
@@ -8,8 +8,9 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
 #include "build/build_config.h"
-#include "content/browser/browser_thread_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -28,29 +29,57 @@
 namespace content {
 
 // ----------------------------------------------------------------------------
-// BrowserProcessSubThread
-//
-// This simple thread object is used for the specialized threads that the
-// BrowserProcess spins up.
+// A BrowserProcessSubThread is a physical thread backing a BrowserThread.
 //
 // Applications must initialize the COM library before they can call
 // COM library functions other than CoGetMalloc and memory allocation
 // functions, so this class initializes COM for those users.
-class CONTENT_EXPORT BrowserProcessSubThread : public BrowserThreadImpl {
+class CONTENT_EXPORT BrowserProcessSubThread : public base::Thread {
  public:
+  // Constructs a BrowserProcessSubThread for |identifier|.
   explicit BrowserProcessSubThread(BrowserThread::ID identifier);
-  BrowserProcessSubThread(BrowserThread::ID identifier,
-                          base::MessageLoop* message_loop);
   ~BrowserProcessSubThread() override;
 
+  // Registers this thread to represent |identifier_| in the browser_thread.h
+  // API. This thread must already be running when this is called. This can only
+  // be called once per BrowserProcessSubThread instance.
+  void RegisterAsBrowserThread();
+
+  // Ideally there wouldn't be a special blanket allowance to block the
+  // BrowserThreads in tests but TestBrowserThreadImpl previously bypassed
+  // BrowserProcessSubThread and hence wasn't subject to ThreadRestrictions...
+  // Flipping that around in favor of explicit scoped allowances would be
+  // preferable but a non-trivial amount of work. Can only be called before
+  // starting this BrowserProcessSubThread.
+  void AllowBlockingForTesting();
+
  protected:
   void Init() override;
+  void Run(base::RunLoop* run_loop) override;
   void CleanUp() override;
 
  private:
-  // These methods encapsulate cleanup that needs to happen on the IO thread
-  // before we call the embedder's CleanUp function.
-  void IOThreadPreCleanUp();
+  // Second Init() phase that must happen on this thread but can only happen
+  // after it's promoted to a BrowserThread in |RegisterAsBrowserThread()|.
+  void CompleteInitializationOnBrowserThread();
+
+  // These methods merely forwards to Thread::Run() but are useful to identify
+  // which BrowserThread this represents in stack traces.
+  void UIThreadRun(base::RunLoop* run_loop);
+  void IOThreadRun(base::RunLoop* run_loop);
+
+  // This method encapsulates cleanup that needs to happen on the IO thread.
+  void IOThreadCleanUp();
+
+  const BrowserThread::ID identifier_;
+
+  // BrowserThreads are not allowed to do file I/O nor wait on synchronization
+  // primivives except when explicitly allowed in tests.
+  bool is_blocking_allowed_for_testing_ = false;
+
+  // The BrowserThread registration for this |identifier_|, initialized in
+  // RegisterAsBrowserThread().
+  std::unique_ptr<BrowserThreadImpl> browser_thread_;
 
 #if defined (OS_WIN)
   std::unique_ptr<base::win::ScopedCOMInitializer> com_initializer_;
@@ -59,6 +88,8 @@
   // Each specialized thread has its own notification service.
   std::unique_ptr<NotificationService> notification_service_;
 
+  THREAD_CHECKER(browser_thread_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessSubThread);
 };
 
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index b8b6b20..c679f3f 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -7,41 +7,21 @@
 #include <string>
 #include <utility>
 
-#include "base/atomicops.h"
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
 #include "base/threading/platform_thread.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/public/browser/browser_thread_delegate.h"
 #include "content/public/browser/content_browser_client.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#endif
-
 namespace content {
 
 namespace {
 
-// Friendly names for the well-known threads.
-static const char* const g_browser_thread_names[BrowserThread::ID_COUNT] = {
-  "",  // UI (name assembled in browser_main.cc).
-  "Chrome_IOThread",  // IO
-};
-
-static const char* GetThreadName(BrowserThread::ID thread) {
-  if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
-    return g_browser_thread_names[thread];
-  if (thread == BrowserThread::UI)
-    return "Chrome_UIThread";
-  return "Unknown Thread";
-}
-
 // An implementation of SingleThreadTaskRunner to be used in conjunction
 // with BrowserThread.
 // TODO(gab): Consider replacing this with |g_globals->task_runners| -- only
@@ -99,17 +79,12 @@
 enum BrowserThreadState {
   // BrowserThread::ID isn't associated with anything yet.
   UNINITIALIZED = 0,
-  // BrowserThread::ID is associated with a BrowserThreadImpl instance but the
-  // underlying thread hasn't started yet.
-  INITIALIZED,
   // BrowserThread::ID is associated to a TaskRunner and is accepting tasks.
   RUNNING,
   // BrowserThread::ID no longer accepts tasks.
   SHUTDOWN
 };
 
-using BrowserThreadDelegateAtomicPtr = base::subtle::AtomicWord;
-
 struct BrowserThreadGlobals {
   // This lock protects |task_runners| and |states|. Do not read or modify those
   // arrays without holding this lock. Do not block while holding this lock.
@@ -124,252 +99,18 @@
 
   // Holds the state of each BrowserThread::ID.
   BrowserThreadState states[BrowserThread::ID_COUNT] = {};
-
-  // Only atomic operations are used on this pointer. The delegate isn't owned
-  // by BrowserThreadGlobals, rather by whoever calls
-  // BrowserThread::SetIOThreadDelegate.
-  BrowserThreadDelegateAtomicPtr io_thread_delegate = 0;
-
-  // This locks protects |is_io_thread_initialized|. Do not read or modify this
-  // variable without holding this lock.
-  base::Lock io_thread_lock;
-
-  // A flag indicates whether the BrowserThreadDelegate of the BrowserThread::IO
-  // thread has been initialized.
-  bool is_io_thread_initialized = false;
 };
 
 base::LazyInstance<BrowserThreadGlobals>::Leaky
     g_globals = LAZY_INSTANCE_INITIALIZER;
 
-void InitIOThreadDelegateOnIOThread() {
-  BrowserThreadDelegateAtomicPtr delegate =
-      base::subtle::NoBarrier_Load(&g_globals.Get().io_thread_delegate);
-  if (delegate)
-    reinterpret_cast<BrowserThreadDelegate*>(delegate)->Init();
-}
-
-bool IsIOThreadInitialized() {
-  BrowserThreadGlobals& globals = g_globals.Get();
-  base::AutoLock lock(globals.io_thread_lock);
-  return globals.is_io_thread_initialized;
-}
-
-void SetIsIOThreadInitialized(bool is_io_thread_initialized) {
-  BrowserThreadGlobals& globals = g_globals.Get();
-  base::AutoLock lock(globals.io_thread_lock);
-  globals.is_io_thread_initialized = is_io_thread_initialized;
-}
-
-}  // namespace
-
-BrowserThreadImpl::BrowserThreadImpl(ID identifier)
-    : Thread(GetThreadName(identifier)), identifier_(identifier) {
-  Initialize();
-}
-
-BrowserThreadImpl::BrowserThreadImpl(ID identifier,
-                                     base::MessageLoop* message_loop)
-    : Thread(GetThreadName(identifier)), identifier_(identifier) {
-  SetMessageLoop(message_loop);
-  Initialize();
-
-  // If constructed with an explicit message loop, this is a fake
-  // BrowserThread which runs on the current thread.
-  BrowserThreadGlobals& globals = g_globals.Get();
-  base::AutoLock lock(globals.lock);
-
-  DCHECK(!globals.task_runners[identifier_]);
-  globals.task_runners[identifier_] = task_runner();
-
-  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
-  globals.states[identifier_] = BrowserThreadState::RUNNING;
-}
-
-void BrowserThreadImpl::Init() {
-#if DCHECK_IS_ON()
-  {
-    BrowserThreadGlobals& globals = g_globals.Get();
-    base::AutoLock lock(globals.lock);
-    // |globals| should already have been initialized for |identifier_| in
-    // BrowserThreadImpl::StartWithOptions(). If this isn't the case it's likely
-    // because this BrowserThreadImpl's owner incorrectly used Thread::Start.*()
-    // instead of BrowserThreadImpl::Start.*().
-    DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
-    DCHECK(globals.task_runners[identifier_]);
-    DCHECK(globals.task_runners[identifier_]->RunsTasksInCurrentSequence());
-  }
-#endif  // DCHECK_IS_ON()
-}
-
-// We disable optimizations for this block of functions so the compiler doesn't
-// merge them all together.
-MSVC_DISABLE_OPTIMIZE()
-MSVC_PUSH_DISABLE_WARNING(4748)
-
-NOINLINE void BrowserThreadImpl::UIThreadRun(base::RunLoop* run_loop) {
-  volatile int line_number = __LINE__;
-  Thread::Run(run_loop);
-  CHECK_GT(line_number, 0);
-}
-
-NOINLINE void BrowserThreadImpl::IOThreadRun(base::RunLoop* run_loop) {
-  volatile int line_number = __LINE__;
-  Thread::Run(run_loop);
-  CHECK_GT(line_number, 0);
-}
-
-MSVC_POP_WARNING()
-MSVC_ENABLE_OPTIMIZE();
-
-void BrowserThreadImpl::Run(base::RunLoop* run_loop) {
-#if defined(OS_ANDROID)
-  // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
-  // Though it may create unnecessary VM thread objects, keeping thread name
-  // gives more benefit in debugging in the platform.
-  if (!thread_name().empty()) {
-    base::android::AttachCurrentThreadWithName(thread_name());
-  }
-#endif
-
-  BrowserThread::ID thread_id = ID_COUNT;
-  CHECK(GetCurrentThreadIdentifier(&thread_id));
-  CHECK_EQ(identifier_, thread_id);
-
-  switch (identifier_) {
-    case BrowserThread::UI:
-      return UIThreadRun(run_loop);
-    case BrowserThread::IO:
-      return IOThreadRun(run_loop);
-    case BrowserThread::ID_COUNT:
-      CHECK(false);  // This shouldn't actually be reached!
-      break;
-  }
-
-  // |identifier_| must be set to a valid enum value in the constructor, so it
-  // should be impossible to reach here.
-  CHECK(false);
-}
-
-void BrowserThreadImpl::CleanUp() {
-  BrowserThreadGlobals& globals = g_globals.Get();
-
-  if (identifier_ == BrowserThread::IO && IsIOThreadInitialized()) {
-    BrowserThreadDelegateAtomicPtr delegate =
-        base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
-    if (delegate)
-      reinterpret_cast<BrowserThreadDelegate*>(delegate)->CleanUp();
-    SetIsIOThreadInitialized(false);
-  }
-
-  // Change the state to SHUTDOWN so that PostTaskHelper stops accepting tasks
-  // for this thread. Do not clear globals.task_runners[identifier_] so that
-  // BrowserThread::CurrentlyOn() works from the MessageLoop's
-  // DestructionObservers.
-  base::AutoLock lock(globals.lock);
-  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
-  globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
-}
-
-void BrowserThreadImpl::Initialize() {
-  BrowserThreadGlobals& globals = g_globals.Get();
-
-  base::AutoLock lock(globals.lock);
-  DCHECK_GE(identifier_, 0);
-  DCHECK_LT(identifier_, ID_COUNT);
-  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
-  globals.states[identifier_] = BrowserThreadState::INITIALIZED;
-}
-
-// static
-void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
-  BrowserThreadGlobals& globals = g_globals.Get();
-
-  base::AutoLock lock(globals.lock);
-  DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
-  globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
-  globals.task_runners[identifier] = nullptr;
-  if (identifier == BrowserThread::IO)
-    SetIOThreadDelegate(nullptr);
-}
-
-void BrowserThreadImpl::InitIOThreadDelegate() {
-  DCHECK(!IsIOThreadInitialized());
-
-  SetIsIOThreadInitialized(true);
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                          base::BindOnce(&InitIOThreadDelegateOnIOThread));
-}
-
-BrowserThreadImpl::~BrowserThreadImpl() {
-  // All Thread subclasses must call Stop() in the destructor. This is
-  // doubly important here as various bits of code check they are on
-  // the right BrowserThread.
-  Stop();
-
-  BrowserThreadGlobals& globals = g_globals.Get();
-  base::AutoLock lock(globals.lock);
-  // This thread should have gone through Cleanup() as part of Stop() and be in
-  // the SHUTDOWN state already (unless it uses an externally provided
-  // MessageLoop instead of a real underlying thread and thus doesn't go through
-  // Cleanup()).
-  if (using_external_message_loop()) {
-    DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
-    globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
-  } else {
-    DCHECK_EQ(globals.states[identifier_], BrowserThreadState::SHUTDOWN);
-  }
-#if DCHECK_IS_ON()
-  // Double check that the threads are ordered correctly in the enumeration.
-  for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
-    DCHECK(globals.states[i] == BrowserThreadState::SHUTDOWN ||
-           globals.states[i] == BrowserThreadState::UNINITIALIZED)
-        << "Threads must be listed in the reverse order that they die";
-  }
-#endif
-}
-
-bool BrowserThreadImpl::Start() {
-  return StartWithOptions(base::Thread::Options());
-}
-
-bool BrowserThreadImpl::StartWithOptions(const Options& options) {
-  BrowserThreadGlobals& globals = g_globals.Get();
-
-  // Holding the lock is necessary when kicking off the thread to ensure
-  // |states| and |task_runners| are updated before it gets to query them.
-  base::AutoLock lock(globals.lock);
-
-  bool result = Thread::StartWithOptions(options);
-
-  // Although the thread is starting asynchronously, the MessageLoop is already
-  // ready to accept tasks and as such this BrowserThreadImpl is considered as
-  // "running".
-  DCHECK(!globals.task_runners[identifier_]);
-  globals.task_runners[identifier_] = task_runner();
-  DCHECK(globals.task_runners[identifier_]);
-
-  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
-  globals.states[identifier_] = BrowserThreadState::RUNNING;
-
-  return result;
-}
-
-bool BrowserThreadImpl::StartAndWaitForTesting() {
-  if (!Start())
-    return false;
-  WaitUntilThreadStarted();
-  return true;
-}
-
-// static
-bool BrowserThreadImpl::PostTaskHelper(BrowserThread::ID identifier,
-                                       const base::Location& from_here,
-                                       base::OnceClosure task,
-                                       base::TimeDelta delay,
-                                       bool nestable) {
+bool PostTaskHelper(BrowserThread::ID identifier,
+                    const base::Location& from_here,
+                    base::OnceClosure task,
+                    base::TimeDelta delay,
+                    bool nestable) {
   DCHECK_GE(identifier, 0);
-  DCHECK_LT(identifier, ID_COUNT);
+  DCHECK_LT(identifier, BrowserThread::ID_COUNT);
   // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
   // order of lifetime.  So no need to lock if we know that the target thread
   // outlives current thread as that implies the current thread only ever sees
@@ -377,9 +118,9 @@
   // Note: since the array is so small, ok to loop instead of creating a map,
   // which would require a lock because std::map isn't thread safe, defeating
   // the whole purpose of this optimization.
-  BrowserThread::ID current_thread = ID_COUNT;
+  BrowserThread::ID current_thread = BrowserThread::ID_COUNT;
   bool target_thread_outlives_current =
-      GetCurrentThreadIdentifier(&current_thread) &&
+      BrowserThreadImpl::GetCurrentThreadIdentifier(&current_thread) &&
       current_thread >= identifier;
 
   BrowserThreadGlobals& globals = g_globals.Get();
@@ -412,6 +153,56 @@
   return accepting_tasks;
 }
 
+}  // namespace
+
+BrowserThreadImpl::BrowserThreadImpl(
+    ID identifier,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : identifier_(identifier) {
+  DCHECK(task_runner);
+
+  BrowserThreadGlobals& globals = g_globals.Get();
+
+  base::AutoLock lock(globals.lock);
+  DCHECK_GE(identifier_, 0);
+  DCHECK_LT(identifier_, ID_COUNT);
+  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
+  globals.states[identifier_] = BrowserThreadState::RUNNING;
+  globals.task_runners[identifier_] = std::move(task_runner);
+}
+
+BrowserThreadImpl::~BrowserThreadImpl() {
+  BrowserThreadGlobals& globals = g_globals.Get();
+  base::AutoLock lock(globals.lock);
+
+  DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
+  globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
+}
+
+// static
+void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
+  BrowserThreadGlobals& globals = g_globals.Get();
+
+  base::AutoLock lock(globals.lock);
+  DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
+  globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
+  globals.task_runners[identifier] = nullptr;
+}
+
+// static
+const char* BrowserThreadImpl::GetThreadName(BrowserThread::ID thread) {
+  static const char* const kBrowserThreadNames[BrowserThread::ID_COUNT] = {
+      "",                 // UI (name assembled in browser_main_loop.cc).
+      "Chrome_IOThread",  // IO
+  };
+
+  if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
+    return kBrowserThreadNames[thread];
+  if (thread == BrowserThread::UI)
+    return "Chrome_UIThread";
+  return "Unknown Thread";
+}
+
 // static
 void BrowserThread::PostAfterStartupTask(
     const base::Location& from_here,
@@ -430,13 +221,7 @@
   base::AutoLock lock(globals.lock);
   DCHECK_GE(identifier, 0);
   DCHECK_LT(identifier, ID_COUNT);
-  bool running =
-      globals.states[identifier] == BrowserThreadState::INITIALIZED ||
-      globals.states[identifier] == BrowserThreadState::RUNNING;
-  if (identifier != BrowserThread::IO)
-    return running;
-
-  return running && IsIOThreadInitialized();
+  return globals.states[identifier] == BrowserThreadState::RUNNING;
 }
 
 // static
@@ -456,7 +241,7 @@
     actual_name = "Unknown Thread";
 
   std::string result = "Must be called on ";
-  result += GetThreadName(expected);
+  result += BrowserThreadImpl::GetThreadName(expected);
   result += "; actually called on ";
   result += actual_name;
   result += ".";
@@ -479,8 +264,8 @@
 bool BrowserThread::PostTask(ID identifier,
                              const base::Location& from_here,
                              base::OnceClosure task) {
-  return BrowserThreadImpl::PostTaskHelper(
-      identifier, from_here, std::move(task), base::TimeDelta(), true);
+  return PostTaskHelper(identifier, from_here, std::move(task),
+                        base::TimeDelta(), true);
 }
 
 // static
@@ -488,16 +273,15 @@
                                     const base::Location& from_here,
                                     base::OnceClosure task,
                                     base::TimeDelta delay) {
-  return BrowserThreadImpl::PostTaskHelper(identifier, from_here,
-                                           std::move(task), delay, true);
+  return PostTaskHelper(identifier, from_here, std::move(task), delay, true);
 }
 
 // static
 bool BrowserThread::PostNonNestableTask(ID identifier,
                                         const base::Location& from_here,
                                         base::OnceClosure task) {
-  return BrowserThreadImpl::PostTaskHelper(
-      identifier, from_here, std::move(task), base::TimeDelta(), false);
+  return PostTaskHelper(identifier, from_here, std::move(task),
+                        base::TimeDelta(), false);
 }
 
 // static
@@ -505,8 +289,7 @@
                                                const base::Location& from_here,
                                                base::OnceClosure task,
                                                base::TimeDelta delay) {
-  return BrowserThreadImpl::PostTaskHelper(identifier, from_here,
-                                           std::move(task), delay, false);
+  return PostTaskHelper(identifier, from_here, std::move(task), delay, false);
 }
 
 // static
@@ -545,16 +328,4 @@
   return g_task_runners.Get().proxies[identifier];
 }
 
-// static
-void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) {
-  BrowserThreadGlobals& globals = g_globals.Get();
-  BrowserThreadDelegateAtomicPtr old_delegate =
-      base::subtle::NoBarrier_AtomicExchange(
-          &globals.io_thread_delegate,
-          reinterpret_cast<BrowserThreadDelegateAtomicPtr>(delegate));
-
-  // This catches registration when previously registered.
-  DCHECK(!delegate || !old_delegate);
-}
-
 }  // namespace content
diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h
index 5457e26..46ba1c8 100644
--- a/content/browser/browser_thread_impl.h
+++ b/content/browser/browser_thread_impl.h
@@ -5,47 +5,31 @@
 #ifndef CONTENT_BROWSER_BROWSER_THREAD_IMPL_H_
 #define CONTENT_BROWSER_BROWSER_THREAD_IMPL_H_
 
-#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
 
-namespace base {
-class MessageLoop;
-class RunLoop;
-}
-
-namespace base {
-class Location;
-}
-
 namespace content {
 
+class BrowserMainLoop;
+class BrowserProcessSubThread;
+class TestBrowserThread;
+
+// BrowserThreadImpl is a scoped object which maps a SingleThreadTaskRunner to a
+// BrowserThread::ID. On ~BrowserThreadImpl() that ID enters a SHUTDOWN state
+// (in which BrowserThread::IsThreadInitialized() returns false) but the mapping
+// isn't undone to avoid shutdown races (the task runner is free to stop
+// accepting tasks however).
+//
 // Very few users should use this directly. To mock BrowserThreads, tests should
 // use TestBrowserThreadBundle instead.
-class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread,
-                                         public base::Thread {
+class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread {
  public:
-  // Construct a BrowserThreadImpl with the supplied identifier.  It is an error
-  // to construct a BrowserThreadImpl that already exists.
-  explicit BrowserThreadImpl(BrowserThread::ID identifier);
+  ~BrowserThreadImpl();
 
-  // Special constructor for the main (UI) thread and unittests. If a
-  // |message_loop| is provied, we use a dummy thread here since the main
-  // thread already exists.
-  BrowserThreadImpl(BrowserThread::ID identifier,
-                    base::MessageLoop* message_loop);
-  ~BrowserThreadImpl() override;
-
-  bool Start();
-  bool StartWithOptions(const Options& options);
-  bool StartAndWaitForTesting();
-  // Called only by the BrowserThread::IO thread to initialize its
-  // BrowserThreadDelegate after the thread is created. See
-  // https://crbug.com/729596.
-  void InitIOThreadDelegate();
+  // Returns the thread name for |identifier|.
+  static const char* GetThreadName(BrowserThread::ID identifier);
 
   // Resets globals for |identifier|. Used in tests to clear global state that
   // would otherwise leak to the next test. Globals are not otherwise fully
@@ -55,35 +39,19 @@
   // |identifier|.
   static void ResetGlobalsForTesting(BrowserThread::ID identifier);
 
- protected:
-  void Init() override;
-  void Run(base::RunLoop* run_loop) override;
-  void CleanUp() override;
-
  private:
-  // We implement all the functionality of the public BrowserThread
-  // functions, but state is stored in the BrowserThreadImpl to keep
-  // the API cleaner. Therefore make BrowserThread a friend class.
-  friend class BrowserThread;
+  // Restrict instantiation to BrowserProcessSubThread as it performs important
+  // initialization that shouldn't be bypassed (except by BrowserMainLoop for
+  // the main thread).
+  friend class BrowserProcessSubThread;
+  friend class BrowserMainLoop;
+  // TestBrowserThread is also allowed to construct this when instantiating fake
+  // threads.
+  friend class TestBrowserThread;
 
-  // The following are unique function names that makes it possible to tell
-  // the thread id from the callstack alone in crash dumps.
-  void UIThreadRun(base::RunLoop* run_loop);
-  void ProcessLauncherThreadRun(base::RunLoop* run_loop);
-  void IOThreadRun(base::RunLoop* run_loop);
-
-  static bool PostTaskHelper(BrowserThread::ID identifier,
-                             const base::Location& from_here,
-                             base::OnceClosure task,
-                             base::TimeDelta delay,
-                             bool nestable);
-
-  // Common initialization code for the constructors.
-  void Initialize();
-
-  // For testing.
-  friend class ContentTestSuiteBaseListener;
-  friend class TestBrowserThreadBundle;
+  // Binds |identifier| to |task_runner| for the browser_thread.h API.
+  BrowserThreadImpl(BrowserThread::ID identifier,
+                    scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // The identifier of this thread.  Only one thread can exist with a given
   // identifier at a given time.
diff --git a/content/browser/browser_thread_unittest.cc b/content/browser/browser_thread_unittest.cc
index 6fc8e70..703fe34 100644
--- a/content/browser/browser_thread_unittest.cc
+++ b/content/browser/browser_thread_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/browser_process_sub_thread.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -31,17 +32,22 @@
 
  protected:
   void SetUp() override {
-    ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI));
-    io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO));
+    ui_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::UI);
     ui_thread_->Start();
-    io_thread_->Start();
+
+    io_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::IO);
+    base::Thread::Options io_options;
+    io_options.message_loop_type = base::MessageLoop::TYPE_IO;
+    io_thread_->StartWithOptions(io_options);
+
+    ui_thread_->RegisterAsBrowserThread();
+    io_thread_->RegisterAsBrowserThread();
   }
 
   void TearDown() override {
-    StopUIThread();
-    io_thread_->Stop();
-    ui_thread_ = nullptr;
-    io_thread_ = nullptr;
+    io_thread_.reset();
+    ui_thread_.reset();
+
     BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI);
     BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
   }
@@ -73,8 +79,8 @@
   };
 
  private:
-  std::unique_ptr<BrowserThreadImpl> ui_thread_;
-  std::unique_ptr<BrowserThreadImpl> io_thread_;
+  std::unique_ptr<BrowserProcessSubThread> ui_thread_;
+  std::unique_ptr<BrowserProcessSubThread> io_thread_;
   // It's kind of ugly to make this mutable - solely so we can post the Quit
   // Task from Release(). This should be fixed.
   mutable base::MessageLoop loop_;
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index 062fba3..12eb690 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -148,7 +148,6 @@
 
   network::ResourceResponseHead head;
   std::unique_ptr<net::RedirectInfo> redirect_info;
-  base::Optional<net::SSLInfo> ssl_info;
   network::mojom::DownloadedTempFilePtr downloaded_file;
   std::vector<uint8_t> cached_metadata;
   size_t encoded_length = 0;
@@ -233,7 +232,6 @@
   // network::mojom::URLLoaderClient methods
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override;
@@ -744,7 +742,6 @@
     DCHECK_EQ(State::kResponseReceived, state_);
     DCHECK(!body_reader_);
     client_->OnReceiveResponse(response_metadata_->head,
-                               response_metadata_->ssl_info,
                                std::move(response_metadata_->downloaded_file));
     response_metadata_.reset();
     loader_->ResumeReadingBodyFromNet();
@@ -897,7 +894,6 @@
 
 void InterceptionJob::SendResponse(const base::StringPiece& body) {
   client_->OnReceiveResponse(response_metadata_->head,
-                             response_metadata_->ssl_info,
                              std::move(response_metadata_->downloaded_file));
 
   // We shouldn't be able to transfer a string that big over the protocol,
@@ -1062,19 +1058,17 @@
 // URLLoaderClient methods
 void InterceptionJob::OnReceiveResponse(
     const network::ResourceResponseHead& head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   state_ = State::kResponseReceived;
   DCHECK(!response_metadata_);
   if (!(stage_ & InterceptionStage::RESPONSE)) {
-    client_->OnReceiveResponse(head, ssl_info, std::move(downloaded_file));
+    client_->OnReceiveResponse(head, std::move(downloaded_file));
     return;
   }
   loader_->PauseReadingBodyFromNet();
   client_binding_.PauseIncomingMethodCallProcessing();
 
   response_metadata_ = std::make_unique<ResponseMetadata>(head);
-  response_metadata_->ssl_info = ssl_info;
   response_metadata_->downloaded_file = std::move(downloaded_file);
 
   NotifyClient(BuildRequestInfo(&head));
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 4dc3e796..a19ad9a 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1045,20 +1045,14 @@
 namespace {
 
 std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
-    const network::ResourceResponseInfo& info) {
-  if (info.certificate.empty())
+    const net::SSLInfo& ssl_info) {
+  if (!ssl_info.cert)
     return nullptr;
-  scoped_refptr<net::X509Certificate> cert(
-      net::X509Certificate::CreateFromBytes(info.certificate[0].data(),
-                                            info.certificate[0].size()));
-  if (!cert)
-    return nullptr;
-
   std::unique_ptr<
       protocol::Array<protocol::Network::SignedCertificateTimestamp>>
       signed_certificate_timestamp_list =
           protocol::Array<Network::SignedCertificateTimestamp>::create();
-  for (auto const& sct : info.signed_certificate_timestamps) {
+  for (auto const& sct : ssl_info.signed_certificate_timestamps) {
     std::unique_ptr<protocol::Network::SignedCertificateTimestamp>
         signed_certificate_timestamp =
             Network::SignedCertificateTimestamp::Create()
@@ -1082,7 +1076,7 @@
   }
   std::vector<std::string> san_dns;
   std::vector<std::string> san_ip;
-  cert->GetSubjectAltName(&san_dns, &san_ip);
+  ssl_info.cert->GetSubjectAltName(&san_dns, &san_ip);
   std::unique_ptr<Array<String>> san_list = Array<String>::create();
   for (const std::string& san : san_dns)
     san_list->addItem(san);
@@ -1092,23 +1086,27 @@
             .ToString());
   }
 
-  int ssl_version =
-      net::SSLConnectionStatusToVersion(info.ssl_connection_status);
-  const char* protocol;
-  net::SSLVersionToString(&protocol, ssl_version);
+  const char* protocol = "";
+  const char* key_exchange = "";
+  const char* cipher = "";
+  const char* mac = nullptr;
 
-  const char* key_exchange;
-  const char* cipher;
-  const char* mac;
-  bool is_aead;
-  bool is_tls13;
-  uint16_t cipher_suite =
-      net::SSLConnectionStatusToCipherSuite(info.ssl_connection_status);
-  net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
-                               &is_tls13, cipher_suite);
-  if (key_exchange == nullptr) {
-    DCHECK(is_tls13);
-    key_exchange = "";
+  int ssl_version =
+      net::SSLConnectionStatusToVersion(ssl_info.connection_status);
+
+  if (ssl_info.connection_status) {
+    net::SSLVersionToString(&protocol, ssl_version);
+
+    bool is_aead;
+    bool is_tls13;
+    uint16_t cipher_suite =
+        net::SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
+    net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
+                                 &is_tls13, cipher_suite);
+    if (key_exchange == nullptr) {
+      DCHECK(is_tls13);
+      key_exchange = "";
+    }
   }
 
   std::unique_ptr<protocol::Network::SecurityDetails> security_details =
@@ -1116,25 +1114,24 @@
           .SetProtocol(protocol)
           .SetKeyExchange(key_exchange)
           .SetCipher(cipher)
-          .SetSubjectName(cert->subject().common_name)
+          .SetSubjectName(ssl_info.cert->subject().common_name)
           .SetSanList(std::move(san_list))
-          .SetIssuer(cert->issuer().common_name)
-          .SetValidFrom(cert->valid_start().ToDoubleT())
-          .SetValidTo(cert->valid_expiry().ToDoubleT())
+          .SetIssuer(ssl_info.cert->issuer().common_name)
+          .SetValidFrom(ssl_info.cert->valid_start().ToDoubleT())
+          .SetValidTo(ssl_info.cert->valid_expiry().ToDoubleT())
           .SetCertificateId(0)  // Keep this in protocol for compatability.
           .SetSignedCertificateTimestampList(
               std::move(signed_certificate_timestamp_list))
           .Build();
 
-  if (info.ssl_key_exchange_group != 0) {
+  if (ssl_info.key_exchange_group != 0) {
     const char* key_exchange_group =
-        SSL_get_curve_name(info.ssl_key_exchange_group);
+        SSL_get_curve_name(ssl_info.key_exchange_group);
     if (key_exchange_group)
       security_details->SetKeyExchangeGroup(key_exchange_group);
   }
   if (mac)
     security_details->SetMac(mac);
-
   return security_details;
 }
 
@@ -1199,7 +1196,8 @@
   response->SetProtocol(GetProtocol(url, info));
   response->SetRemoteIPAddress(info.socket_address.HostForURL());
   response->SetRemotePort(info.socket_address.port());
-  response->SetSecurityDetails(BuildSecurityDetails(info));
+  if (info.ssl_info.has_value())
+    response->SetSecurityDetails(BuildSecurityDetails(*info.ssl_info));
 
   return response;
 }
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 38d76a7..8bf1bce 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -159,7 +159,7 @@
     network::ResourceResponseHead head;
     head.mime_type = "text/html";
     head.charset = "utf-8";
-    client->OnReceiveResponse(head, base::nullopt, nullptr);
+    client->OnReceiveResponse(head, nullptr);
     client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
     client_ = std::move(client);
 
@@ -554,7 +554,7 @@
           base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
                              head.mime_type.c_str()));
     }
-    client->OnReceiveResponse(head, base::nullopt, nullptr);
+    client->OnReceiveResponse(head, nullptr);
     client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
     client_ = std::move(client);
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index c6c6ebc..9df4090 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -810,7 +810,6 @@
     const scoped_refptr<network::ResourceResponse>& response,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<StreamHandle> body,
-    const net::SSLInfo& ssl_info,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
     bool is_download,
@@ -918,7 +917,8 @@
   response_ = response;
   body_ = std::move(body);
   url_loader_client_endpoints_ = std::move(url_loader_client_endpoints);
-  ssl_info_ = ssl_info;
+  ssl_info_ = response->head.ssl_info.has_value() ? *response->head.ssl_info
+                                                  : net::SSLInfo();
   is_download_ = is_download;
 
   subresource_loader_params_ = std::move(subresource_loader_params);
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 30cc4cb..75975ca 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -236,7 +236,6 @@
       const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<StreamHandle> body,
-      const net::SSLInfo& ssl_info,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& request_id,
       bool is_download,
diff --git a/content/browser/histogram_internals_url_loader.cc b/content/browser/histogram_internals_url_loader.cc
index fa8e3a0..1c24e26 100644
--- a/content/browser/histogram_internals_url_loader.cc
+++ b/content/browser/histogram_internals_url_loader.cc
@@ -19,7 +19,7 @@
   network::ResourceResponseHead resource_response;
   resource_response.headers = headers;
   resource_response.mime_type = "text/html";
-  client->OnReceiveResponse(resource_response, base::nullopt, nullptr);
+  client->OnReceiveResponse(resource_response, nullptr);
 
   base::StatisticsRecorder::ImportProvidedHistograms();
   std::string data = HistogramInternalsRequestJob::GenerateHTML(request.url);
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index 130a2fe..b0af434 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -194,12 +194,13 @@
                                      response->head.download_file_path);
   }
 
-  base::Optional<net::SSLInfo> ssl_info;
-  if (url_loader_options_ &
-      network::mojom::kURLLoadOptionSendSSLInfoWithResponse)
-    ssl_info = request()->ssl_info();
+  if ((url_loader_options_ &
+       network::mojom::kURLLoadOptionSendSSLInfoWithResponse) &&
+      request()->ssl_info().cert) {
+    response->head.ssl_info = request()->ssl_info();
+  }
 
-  url_loader_client_->OnReceiveResponse(response->head, std::move(ssl_info),
+  url_loader_client_->OnReceiveResponse(response->head,
                                         std::move(downloaded_file_ptr));
 
   net::IOBufferWithSize* metadata = GetResponseMetadata(request());
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index 6927e1f7..4c64ea8 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -45,6 +45,7 @@
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/ssl/ssl_info.h"
+#include "net/test/cert_test_util.h"
 #include "net/test/url_request/url_request_mock_data_job.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request.h"
@@ -396,6 +397,13 @@
     handler_->upload_progress_tracker()->current_time_ += delta;
   }
 
+  void SetupRequestSSLInfo() {
+    net::CertificateList certs;
+    ASSERT_TRUE(net::LoadCertificateFiles({"multi-root-B-by-C.pem"}, &certs));
+    ASSERT_EQ(1U, certs.size());
+    const_cast<net::SSLInfo&>(request_->ssl_info()).cert = certs[0];
+  }
+
   TestBrowserThreadBundle thread_bundle_;
   TestResourceDispatcherHostDelegate rdh_delegate_;
   ResourceDispatcherHostImpl rdh_;
@@ -1394,6 +1402,7 @@
 // Test that SSLInfo is not attached to OnResponseStarted when there is no
 // kURLLoadOptionsSendSSLInfoWithResponse option.
 TEST_F(MojoAsyncResourceHandlerTest, SSLInfoOnResponseStarted) {
+  SetupRequestSSLInfo();
   EXPECT_TRUE(CallOnWillStartAndOnResponseStarted());
   EXPECT_FALSE(url_loader_client_.ssl_info());
 }
@@ -1402,6 +1411,7 @@
 // kURLLoadOptionsSendSSLInfoWithResponse option.
 TEST_F(MojoAsyncResourceHandlerSendSSLInfoWithResponseTest,
        SSLInfoOnResponseStarted) {
+  SetupRequestSSLInfo();
   EXPECT_TRUE(CallOnWillStartAndOnResponseStarted());
   EXPECT_TRUE(url_loader_client_.ssl_info());
 }
diff --git a/content/browser/loader/navigation_resource_handler.cc b/content/browser/loader/navigation_resource_handler.cc
index f4bb551..e0ee350 100644
--- a/content/browser/loader/navigation_resource_handler.cc
+++ b/content/browser/loader/navigation_resource_handler.cc
@@ -120,6 +120,8 @@
   ResourceRequestInfoImpl* info = GetRequestInfo();
 
   response->head.encoded_data_length = request()->raw_header_size();
+  if (request()->ssl_info().cert)
+    response->head.ssl_info = request()->ssl_info();
 
   std::unique_ptr<NavigationData> cloned_data;
   if (resource_dispatcher_host_delegate_) {
@@ -132,10 +134,9 @@
       cloned_data = navigation_data->Clone();
   }
 
-  core_->NotifyResponseStarted(response, std::move(stream_handle_),
-                               request()->ssl_info(), std::move(cloned_data),
-                               info->GetGlobalRequestID(), info->IsDownload(),
-                               info->is_stream());
+  core_->NotifyResponseStarted(
+      response, std::move(stream_handle_), std::move(cloned_data),
+      info->GetGlobalRequestID(), info->IsDownload(), info->is_stream());
   HoldController(std::move(controller));
   response_ = response;
 }
diff --git a/content/browser/loader/navigation_url_loader_delegate.h b/content/browser/loader/navigation_url_loader_delegate.h
index c3d6fa5..d7f694a 100644
--- a/content/browser/loader/navigation_url_loader_delegate.h
+++ b/content/browser/loader/navigation_url_loader_delegate.h
@@ -52,7 +52,6 @@
       const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<StreamHandle> body_stream,
-      const net::SSLInfo& ssl_info,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& request_id,
       bool is_download,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 00f5505..687e6a6a 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -98,7 +98,6 @@
 void NavigationURLLoaderImpl::NotifyResponseStarted(
     const scoped_refptr<network::ResourceResponse>& response,
     std::unique_ptr<StreamHandle> body,
-    const net::SSLInfo& ssl_info,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
     bool is_download,
@@ -107,9 +106,10 @@
 
   delegate_->OnResponseStarted(
       response, network::mojom::URLLoaderClientEndpointsPtr(), std::move(body),
-      ssl_info, std::move(navigation_data), request_id, is_download, is_stream,
+      std::move(navigation_data), request_id, is_download, is_stream,
       base::nullopt);
 }
+
 void NavigationURLLoaderImpl::NotifyRequestFailed(
     bool in_cache,
     int net_error,
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index 396939d..7060fce6 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -60,7 +60,6 @@
   void NotifyResponseStarted(
       const scoped_refptr<network::ResourceResponse>& response,
       std::unique_ptr<StreamHandle> body,
-      const net::SSLInfo& ssl_info,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& request_id,
       bool is_download,
diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc
index 0889976..c4683b4 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -50,6 +50,10 @@
   base::WeakPtr<NavigationURLLoaderImplCore> weak_this =
       weak_factory_.GetWeakPtr();
 
+  uint32_t options = network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
+  if (request_info->is_main_frame)
+    options |= network::mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+
   // The ResourceDispatcherHostImpl can be null in unit tests.
   if (ResourceDispatcherHostImpl::Get()) {
     GlobalRequestID global_request_id;  // unused.
@@ -59,8 +63,7 @@
         std::move(navigation_ui_data), this,
         network::mojom::URLLoaderClientPtr(),
         network::mojom::URLLoaderRequest(), service_worker_handle_core,
-        appcache_handle_core, network::mojom::kURLLoadOptionNone,
-        &global_request_id);
+        appcache_handle_core, options, &global_request_id);
   }
 
   // Careful, |this| could be destroyed at this point. Don't notify start if
@@ -121,7 +124,6 @@
 void NavigationURLLoaderImplCore::NotifyResponseStarted(
     network::ResourceResponse* response,
     std::unique_ptr<StreamHandle> body,
-    const net::SSLInfo& ssl_info,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
     bool is_download,
@@ -143,7 +145,7 @@
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(&NavigationURLLoaderImpl::NotifyResponseStarted, loader_,
-                     response->DeepCopy(), std::move(body), ssl_info,
+                     response->DeepCopy(), std::move(body),
                      std::move(navigation_data), request_id, is_download,
                      is_stream));
 }
diff --git a/content/browser/loader/navigation_url_loader_impl_core.h b/content/browser/loader/navigation_url_loader_impl_core.h
index 60986764..5b3bad89 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.h
+++ b/content/browser/loader/navigation_url_loader_impl_core.h
@@ -78,7 +78,6 @@
   // Notifies |loader_| on the UI thread that the response started.
   void NotifyResponseStarted(network::ResourceResponse* response,
                              std::unique_ptr<StreamHandle> body,
-                             const net::SSLInfo& ssl_info,
                              std::unique_ptr<NavigationData> navigation_data,
                              const GlobalRequestID& request_id,
                              bool is_download,
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 2a771ad..dd18c83 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -703,7 +703,6 @@
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     received_response_ = true;
 
@@ -789,9 +788,8 @@
         base::BindOnce(&NavigationURLLoaderNetworkService::OnReceiveResponse,
                        owner_, response->DeepCopy(),
                        std::move(url_loader_client_endpoints),
-                       std::move(ssl_info), std::move(cloned_navigation_data),
-                       global_request_id_, is_download, is_stream,
-                       std::move(downloaded_file)));
+                       std::move(cloned_navigation_data), global_request_id_,
+                       is_download, is_stream, std::move(downloaded_file)));
   }
 
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
@@ -1125,7 +1123,6 @@
 void NavigationURLLoaderNetworkService::OnReceiveResponse(
     scoped_refptr<network::ResourceResponse> response,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
-    const base::Optional<net::SSLInfo>& maybe_ssl_info,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& global_request_id,
     bool is_download,
@@ -1137,13 +1134,10 @@
 
   // TODO(scottmg): This needs to do more of what
   // NavigationResourceHandler::OnResponseStarted() does.
-  net::SSLInfo ssl_info;
-  if (maybe_ssl_info.has_value())
-    ssl_info = maybe_ssl_info.value();
 
   delegate_->OnResponseStarted(
       std::move(response), std::move(url_loader_client_endpoints), nullptr,
-      std::move(ssl_info), std::move(navigation_data), global_request_id,
+      std::move(navigation_data), global_request_id,
       allow_download_ && is_download, is_stream,
       request_controller_->TakeSubresourceLoaderParams());
 }
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index 57708e5..7a3ee67 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -54,7 +54,6 @@
   void OnReceiveResponse(
       scoped_refptr<network::ResourceResponse> response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
-      const base::Optional<net::SSLInfo>& maybe_ssl_info,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& global_request_id,
       bool is_download,
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index c0abbc9..5b6e3d2b 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -76,7 +76,6 @@
 
 void PrefetchURLLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   if (WebPackagePrefetchHandler::IsResponseForWebPackage(response)) {
     DCHECK(!web_package_prefetch_handler_);
@@ -90,8 +89,7 @@
         request_context_getter_, this);
     return;
   }
-  forwarding_client_->OnReceiveResponse(response, ssl_info,
-                                        std::move(downloaded_file));
+  forwarding_client_->OnReceiveResponse(response, std::move(downloaded_file));
 }
 
 void PrefetchURLLoader::OnReceiveRedirect(
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index f15316e8..32ae58a 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -67,7 +67,6 @@
   // network::mojom::URLLoaderClient overrides:
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override;
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index a7cb4ba5..bc4ce200 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -35,7 +35,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/cert/symantec_certs.h"
-#include "net/cert/x509_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator.h"
@@ -116,25 +115,9 @@
         (!net::IsCertStatusError(response->head.cert_status) ||
          net::IsCertStatusMinorError(response->head.cert_status)) &&
         net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
-    if (info->ShouldReportRawHeaders()) {
-      // Only pass these members when the network panel of the DevTools is open,
-      // i.e. ShouldReportRawHeaders() is set. These data are used to populate
-      // the requests in the security panel too.
-      response->head.ssl_connection_status =
-          request->ssl_info().connection_status;
-      response->head.ssl_key_exchange_group =
-          request->ssl_info().key_exchange_group;
-      response->head.signed_certificate_timestamps =
-          request->ssl_info().signed_certificate_timestamps;
-      response->head.certificate.emplace_back(
-          net::x509_util::CryptoBufferAsStringPiece(
-              request->ssl_info().cert->cert_buffer()));
-      for (const auto& cert :
-           request->ssl_info().cert->intermediate_buffers()) {
-        response->head.certificate.emplace_back(
-            net::x509_util::CryptoBufferAsStringPiece(cert.get()));
-      }
-    }
+
+    if (info->ShouldReportRawHeaders())
+      response->head.ssl_info = request->ssl_info();
   } else {
     // We should not have any SSL state.
     DCHECK(!request->ssl_info().cert_status);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c2f3e783..bb52a25 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2647,6 +2647,7 @@
     switches::kReducedReferrerGranularity,
     switches::kRegisterPepperPlugins,
     switches::kRendererStartupDialog,
+    switches::kReportVp9AsAnUnsupportedMimeType,
     switches::kSamplingHeapProfiler,
     switches::kShowPaintRects,
     switches::kStatsCollectionController,
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 6aa7d0c2..5786d95c 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -20,6 +20,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/common/frame_messages.h"
+#include "content/public/browser/devtools_agent_host.h"
 #include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/base/layout.h"
@@ -731,7 +732,8 @@
 }
 
 void RenderWidgetHostInputEventRouter::ReportBubblingScrollToSameView(
-    const blink::WebGestureEvent& event) {
+    const blink::WebGestureEvent& event,
+    const RenderWidgetHostViewBase* view) {
   static auto* type_key = base::debug::AllocateCrashKeyString(
       "same-view-bubble-event-type", base::debug::CrashKeySize::Size32);
   base::debug::ScopedCrashKeyString type_key_value(
@@ -740,6 +742,17 @@
       "same-view-bubble-source-device", base::debug::CrashKeySize::Size32);
   base::debug::ScopedCrashKeyString device_key_value(
       device_key, std::to_string(event.SourceDevice()));
+
+  // Issue 824772 is a potential cause for issue 818214. Report whether
+  // devtools is in use to investigate whether there are other causes.
+  auto* contents = view->host()->delegate()->GetAsWebContents();
+  const bool have_devtools =
+      contents && DevToolsAgentHost::IsDebuggerAttached(contents);
+  static auto* devtools_key = base::debug::AllocateCrashKeyString(
+      "same-view-bubble-have-devtools", base::debug::CrashKeySize::Size32);
+  base::debug::ScopedCrashKeyString devtools_key_value(
+      devtools_key, std::to_string(have_devtools));
+
   base::debug::DumpWithoutCrashing();
 }
 
@@ -822,7 +835,7 @@
     // bubbling.
     // TODO(818214): Remove once this issue no longer occurs.
     if (resending_view == bubbling_gesture_scroll_target_.target) {
-      ReportBubblingScrollToSameView(event);
+      ReportBubblingScrollToSameView(event, resending_view);
       first_bubbling_scroll_target_.target = nullptr;
       bubbling_gesture_scroll_target_.target = nullptr;
       return;
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 6ddb6ef..a81e74f 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -233,7 +233,8 @@
                                         viz::EventSource source) const;
 
   // TODO(818214): Remove once this issue no longer occurs.
-  void ReportBubblingScrollToSameView(const blink::WebGestureEvent& event);
+  void ReportBubblingScrollToSameView(const blink::WebGestureEvent& event,
+                                      const RenderWidgetHostViewBase* view);
 
   // RenderWidgetTargeter::Delegate:
   RenderWidgetTargetResult FindTargetSynchronously(
diff --git a/content/browser/renderer_host/render_widget_host_ns_view_bridge.h b/content/browser/renderer_host/render_widget_host_ns_view_bridge.h
index 0c7056e..ca6fdcf 100644
--- a/content/browser/renderer_host/render_widget_host_ns_view_bridge.h
+++ b/content/browser/renderer_host/render_widget_host_ns_view_bridge.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/strings/string16.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace content {
@@ -32,12 +33,22 @@
   // method is expected to go away).
   virtual RenderWidgetHostViewCocoa* GetRenderWidgetHostViewCocoa() = 0;
 
+  // Remove the NSView from the view heirarchy and destroy it. After this is
+  // called, no calls back into the RenderWidgetHostNSViewClient may be made.
+  virtual void Destroy() = 0;
+
+  // Make the NSView be the first responder of its NSWindow.
+  virtual void MakeFirstResponder() = 0;
+
   // Set the background color of the hosted CALayer.
   virtual void SetBackgroundColor(SkColor color) = 0;
 
   // Call the -[NSView setHidden:] method.
   virtual void SetVisible(bool visible) = 0;
 
+  // Call the -[NSView setToolTipAtMousePoint] method.
+  virtual void SetTooltipText(const base::string16& display_text) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostNSViewBridge);
 };
diff --git a/content/browser/renderer_host/render_widget_host_ns_view_bridge.mm b/content/browser/renderer_host/render_widget_host_ns_view_bridge.mm
index 85ee334..ca2df49 100644
--- a/content/browser/renderer_host/render_widget_host_ns_view_bridge.mm
+++ b/content/browser/renderer_host/render_widget_host_ns_view_bridge.mm
@@ -7,6 +7,7 @@
 #import <Cocoa/Cocoa.h>
 
 #import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
 #import "content/browser/renderer_host/render_widget_host_view_cocoa.h"
 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
 #import "skia/ext/skia_utils_mac.h"
@@ -30,8 +31,11 @@
   ~RenderWidgetHostViewNSViewBridgeLocal() override;
   RenderWidgetHostViewCocoa* GetRenderWidgetHostViewCocoa() override;
 
+  void Destroy() override;
+  void MakeFirstResponder() override;
   void SetBackgroundColor(SkColor color) override;
   void SetVisible(bool visible) override;
+  void SetTooltipText(const base::string16& display_text) override;
 
  private:
   // display::DisplayObserver implementation.
@@ -45,6 +49,9 @@
   // The background CoreAnimation layer which is hosted by |cocoa_view_|.
   base::scoped_nsobject<CALayer> background_layer_;
 
+  // Cached copy of the tooltip text, to avoid redundant calls.
+  base::string16 tooltip_text_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewNSViewBridgeLocal);
 };
 
@@ -72,6 +79,18 @@
   return cocoa_view_;
 }
 
+void RenderWidgetHostViewNSViewBridgeLocal::Destroy() {
+  [cocoa_view_ setClientWasDestroyed];
+  [cocoa_view_ retain];
+  [cocoa_view_ removeFromSuperview];
+  [cocoa_view_ autorelease];
+  cocoa_view_ = nil;
+}
+
+void RenderWidgetHostViewNSViewBridgeLocal::MakeFirstResponder() {
+  [[cocoa_view_ window] makeFirstResponder:cocoa_view_];
+}
+
 void RenderWidgetHostViewNSViewBridgeLocal::SetBackgroundColor(SkColor color) {
   ScopedCAActionDisabler disabler;
   base::ScopedCFTypeRef<CGColorRef> cg_color(
@@ -84,6 +103,30 @@
   [cocoa_view_ setHidden:!visible];
 }
 
+void RenderWidgetHostViewNSViewBridgeLocal::SetTooltipText(
+    const base::string16& tooltip_text) {
+  // Called from the renderer to tell us what the tooltip text should be. It
+  // calls us frequently so we need to cache the value to prevent doing a lot
+  // of repeat work.
+  if (tooltip_text == tooltip_text_ || ![[cocoa_view_ window] isKeyWindow])
+    return;
+  tooltip_text_ = tooltip_text;
+
+  // Maximum number of characters we allow in a tooltip.
+  const size_t kMaxTooltipLength = 1024;
+
+  // Clamp the tooltip length to kMaxTooltipLength. It's a DOS issue on
+  // Windows; we're just trying to be polite. Don't persist the trimmed
+  // string, as then the comparison above will always fail and we'll try to
+  // set it again every single time the mouse moves.
+  base::string16 display_text = tooltip_text_;
+  if (tooltip_text_.length() > kMaxTooltipLength)
+    display_text = tooltip_text_.substr(0, kMaxTooltipLength);
+
+  NSString* tooltip_nsstring = base::SysUTF16ToNSString(display_text);
+  [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring];
+}
+
 void RenderWidgetHostViewNSViewBridgeLocal::OnDisplayMetricsChanged(
     const display::Display& display,
     uint32_t changed_metrics) {
diff --git a/content/browser/renderer_host/render_widget_host_ns_view_client.h b/content/browser/renderer_host/render_widget_host_ns_view_client.h
index 60bcf374..439da91 100644
--- a/content/browser/renderer_host/render_widget_host_ns_view_client.h
+++ b/content/browser/renderer_host/render_widget_host_ns_view_client.h
@@ -23,6 +23,15 @@
   // RenderWidgetHostNSViewBridge, this method is to be removed.
   virtual RenderWidgetHostViewMac* GetRenderWidgetHostViewMac() = 0;
 
+  // Indicates that the RenderWidgetHost is to shut down.
+  virtual void OnNSViewRequestShutdown() = 0;
+
+  // Indicates whether or not the NSView is its NSWindow's first responder.
+  virtual void OnNSViewIsFirstResponderChanged(bool is_first_responder) = 0;
+
+  // Indicates whether or not the NSView's NSWindow is key.
+  virtual void OnNSViewWindowIsKeyChanged(bool is_key) = 0;
+
   // Indicates the NSView's bounds in its NSWindow's DIP coordinate system (with
   // the origin at the upper-left corner), and indicate if the the NSView is
   // attached to an NSWindow (if it is not, then |view_bounds_in_window_dip|'s
diff --git a/content/browser/renderer_host/render_widget_host_view_cocoa.h b/content/browser/renderer_host/render_widget_host_view_cocoa.h
index addae2e..6f5e0fd 100644
--- a/content/browser/renderer_host/render_widget_host_view_cocoa.h
+++ b/content/browser/renderer_host/render_widget_host_view_cocoa.h
@@ -49,8 +49,14 @@
                       NSTextInputClient> {
  @private
   // The communications channel to the RenderWidgetHostViewMac.
+  // TODO(ccameron): When RenderWidgetHostViewCocoa no longer directly accesses
+  // RenderWidgetHostViewMac, then |client_| can be made to be a weak pointer,
+  // and |clientWasDestroyed_| can be replaced with a null-check on |client_|.
   std::unique_ptr<content::RenderWidgetHostNSViewClient> client_;
 
+  // Whether or not it is safe to call back into the |client_| (see above TODO).
+  BOOL clientWasDestroyed_;
+
   // TODO(ccameron): Make all communication with the RenderWidgetHostView go
   // through |client_| and delete this member variable.
   content::RenderWidgetHostViewMac* renderWidgetHostView_;
@@ -196,6 +202,8 @@
 
 - (void)setCanBeKeyView:(BOOL)can;
 - (void)setCloseOnDeactivate:(BOOL)b;
+// Inidicate that the client was destroyed and can't be called back into.
+- (void)setClientWasDestroyed;
 // True for always-on-top special windows (e.g. Balloons and Panels).
 - (BOOL)acceptsMouseEventsWhenInactive;
 // Cancel ongoing composition (abandon the marked text).
diff --git a/content/browser/renderer_host/render_widget_host_view_cocoa.mm b/content/browser/renderer_host/render_widget_host_view_cocoa.mm
index a657c2b..dd52a36 100644
--- a/content/browser/renderer_host/render_widget_host_view_cocoa.mm
+++ b/content/browser/renderer_host/render_widget_host_view_cocoa.mm
@@ -296,6 +296,10 @@
   closeOnDeactivate_ = b;
 }
 
+- (void)setClientWasDestroyed {
+  clientWasDestroyed_ = YES;
+}
+
 - (BOOL)shouldIgnoreMouseEvent:(NSEvent*)theEvent {
   NSWindow* window = [self window];
   // If this is a background window, don't handle mouse movement events. This
@@ -1277,7 +1281,7 @@
 }
 
 - (BOOL)acceptsFirstResponder {
-  if (!renderWidgetHostView_->host())
+  if (clientWasDestroyed_)
     return NO;
 
   return canBeKeyView_;
@@ -1289,7 +1293,7 @@
   if ([responderDelegate_ respondsToSelector:@selector(windowDidBecomeKey)])
     [responderDelegate_ windowDidBecomeKey];
   if ([self window].isKeyWindow && [[self window] firstResponder] == self)
-    renderWidgetHostView_->SetActive(true);
+    client_->OnNSViewWindowIsKeyChanged(true);
 }
 
 - (void)windowDidResignKey:(NSNotification*)notification {
@@ -1304,17 +1308,16 @@
     return;
 
   if ([[self window] firstResponder] == self)
-    renderWidgetHostView_->SetActive(false);
+    client_->OnNSViewWindowIsKeyChanged(false);
 }
 
 - (BOOL)becomeFirstResponder {
-  if (!renderWidgetHostView_->host())
+  if (clientWasDestroyed_)
     return NO;
   if ([responderDelegate_ respondsToSelector:@selector(becomeFirstResponder)])
     [responderDelegate_ becomeFirstResponder];
 
-  renderWidgetHostView_->host()->GotFocus();
-  renderWidgetHostView_->SetTextInputActive(true);
+  client_->OnNSViewIsFirstResponderChanged(true);
 
   // Cancel any onging composition text which was left before we lost focus.
   // TODO(suzhe): We should do it in -resignFirstResponder: method, but
@@ -1337,14 +1340,15 @@
 - (BOOL)resignFirstResponder {
   if ([responderDelegate_ respondsToSelector:@selector(resignFirstResponder)])
     [responderDelegate_ resignFirstResponder];
-  renderWidgetHostView_->SetTextInputActive(false);
-  if (!renderWidgetHostView_->host())
+
+  if (clientWasDestroyed_)
     return YES;
 
-  if (closeOnDeactivate_)
-    renderWidgetHostView_->KillSelf();
-
-  renderWidgetHostView_->host()->LostFocus();
+  client_->OnNSViewIsFirstResponderChanged(false);
+  if (closeOnDeactivate_) {
+    [self setHidden:YES];
+    client_->OnNSViewRequestShutdown();
+  }
 
   // We should cancel any onging composition whenever RWH's Blur() method gets
   // called, because in this case, webkit will confirm the ongoing composition
@@ -1869,11 +1873,15 @@
   if (!renderWidgetHostView_->browser_compositor_)
     return;
 
-  // Update the window's frame, the view's bounds, and the display info, as they
-  // have not been updated while unattached to a window.
+  // Update the window's frame, the view's bounds, focus, and the display info,
+  // as they have not been updated while unattached to a window.
   [self sendWindowFrameInScreenToClient];
   [self sendViewBoundsInWindowToClient];
   [self updateScreenProperties];
+  if (!clientWasDestroyed_) {
+    client_->OnNSViewIsFirstResponderChanged([[self window] firstResponder] ==
+                                             self);
+  }
 
   // If we switch windows (or are removed from the view hierarchy), cancel any
   // open mouse-downs.
@@ -2019,7 +2027,8 @@
 }
 
 - (void)popupWindowWillClose:(NSNotification*)notification {
-  renderWidgetHostView_->KillSelf();
+  [self setHidden:YES];
+  client_->OnNSViewRequestShutdown();
 }
 
 @end
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index d2ff2c2..ea13f3a 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -208,8 +208,6 @@
   // Forwards the mouse event to the renderer.
   void ForwardMouseEvent(const blink::WebMouseEvent& event);
 
-  void KillSelf();
-
   void SetTextInputActive(bool active);
 
   // Returns true and stores first rectangle for character range if the
@@ -283,6 +281,9 @@
 
   // RenderWidgetHostNSViewClient implementation.
   RenderWidgetHostViewMac* GetRenderWidgetHostViewMac() override;
+  void OnNSViewRequestShutdown() override;
+  void OnNSViewIsFirstResponderChanged(bool is_first_responder) override;
+  void OnNSViewWindowIsKeyChanged(bool is_key) override;
   void OnNSViewBoundsInWindowChanged(const gfx::Rect& view_bounds_in_window_dip,
                                      bool attached_to_window) override;
   void OnNSViewWindowFrameInScreenChanged(
@@ -386,6 +387,9 @@
   // Cached copy of the display information pushed to us from the NSView.
   display::Display display_;
 
+  // Whether or not the NSView is first responder.
+  bool is_first_responder_ = false;
+
   // Indicates if the page is loading.
   bool is_loading_;
 
@@ -395,9 +399,6 @@
   // The last scroll offset of the view.
   gfx::Vector2dF last_scroll_offset_;
 
-  // The text to be shown in the tooltip, supplied by the renderer.
-  base::string16 tooltip_text_;
-
   // True when this view acts as a platform view hack for a
   // RenderWidgetHostViewGuest.
   bool is_guest_view_hack_;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 2b5dda27..0e0f144 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -144,13 +144,6 @@
 
 @end
 
-namespace {
-
-// Maximum number of characters we allow in a tooltip.
-const size_t kMaxTooltipLength = 1024;
-
-}  // namespace
-
 namespace content {
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -623,11 +616,11 @@
 }
 
 void RenderWidgetHostViewMac::Focus() {
-  [[cocoa_view() window] makeFirstResponder:cocoa_view()];
+  ns_view_bridge_->MakeFirstResponder();
 }
 
 bool RenderWidgetHostViewMac::HasFocus() const {
-  return [[cocoa_view() window] firstResponder] == cocoa_view();
+  return is_first_responder_;
 }
 
 bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() const {
@@ -792,10 +785,9 @@
               object:popup_window_];
 
   // We've been told to destroy.
-  [cocoa_view() retain];
-  [cocoa_view() removeFromSuperview];
-  [cocoa_view() autorelease];
-
+  if (ns_view_bridge_)
+    ns_view_bridge_->Destroy();
+  ns_view_bridge_.reset();
   [popup_window_ close];
   popup_window_.autorelease();
 
@@ -829,25 +821,9 @@
   RenderWidgetHostViewBase::Destroy();
 }
 
-// Called from the renderer to tell us what the tooltip text should be. It
-// calls us frequently so we need to cache the value to prevent doing a lot
-// of repeat work.
 void RenderWidgetHostViewMac::SetTooltipText(
     const base::string16& tooltip_text) {
-  if (tooltip_text != tooltip_text_ && [[cocoa_view() window] isKeyWindow]) {
-    tooltip_text_ = tooltip_text;
-
-    // Clamp the tooltip length to kMaxTooltipLength. It's a DOS issue on
-    // Windows; we're just trying to be polite. Don't persist the trimmed
-    // string, as then the comparison above will always fail and we'll try to
-    // set it again every single time the mouse moves.
-    base::string16 display_text = tooltip_text_;
-    if (tooltip_text_.length() > kMaxTooltipLength)
-      display_text = tooltip_text_.substr(0, kMaxTooltipLength);
-
-    NSString* tooltip_nsstring = base::SysUTF16ToNSString(display_text);
-    [cocoa_view() setToolTipAtMousePoint:tooltip_nsstring];
-  }
+  ns_view_bridge_->SetTooltipText(tooltip_text);
 }
 
 viz::ScopedSurfaceIdAllocator RenderWidgetHostViewMac::ResizeDueToAutoResize(
@@ -987,10 +963,8 @@
   if (host())
     host()->ForwardMouseEvent(event);
 
-  if (event.GetType() == WebInputEvent::kMouseLeave) {
-    [cocoa_view() setToolTipAtMousePoint:nil];
-    tooltip_text_.clear();
-  }
+  if (event.GetType() == WebInputEvent::kMouseLeave)
+    ns_view_bridge_->SetTooltipText(base::string16());
 }
 
 void RenderWidgetHostViewMac::SetNeedsBeginFrames(bool needs_begin_frames) {
@@ -1013,15 +987,6 @@
   browser_compositor_->SetWantsAnimateOnlyBeginFrames();
 }
 
-void RenderWidgetHostViewMac::KillSelf() {
-  if (!weak_factory_.HasWeakPtrs()) {
-    [cocoa_view() setHidden:YES];
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&RenderWidgetHostViewMac::ShutdownHost,
-                              weak_factory_.GetWeakPtr()));
-  }
-}
-
 bool RenderWidgetHostViewMac::GetLineBreakIndex(
     const std::vector<gfx::Rect>& bounds,
     const gfx::Range& range,
@@ -1261,7 +1226,7 @@
   [NSCursor hide];
 
   // Clear the tooltip window.
-  SetTooltipText(base::string16());
+  ns_view_bridge_->SetTooltipText(base::string16());
 
   return true;
 }
@@ -1510,6 +1475,32 @@
   return this;
 }
 
+void RenderWidgetHostViewMac::OnNSViewRequestShutdown() {
+  if (!weak_factory_.HasWeakPtrs()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&RenderWidgetHostViewMac::ShutdownHost,
+                                  weak_factory_.GetWeakPtr()));
+  }
+}
+
+void RenderWidgetHostViewMac::OnNSViewIsFirstResponderChanged(
+    bool is_first_responder) {
+  if (is_first_responder_ == is_first_responder)
+    return;
+  is_first_responder_ = is_first_responder;
+  if (is_first_responder_) {
+    host()->GotFocus();
+    SetTextInputActive(true);
+  } else {
+    SetTextInputActive(false);
+    host()->LostFocus();
+  }
+}
+
+void RenderWidgetHostViewMac::OnNSViewWindowIsKeyChanged(bool is_key) {
+  SetActive(is_key);
+}
+
 void RenderWidgetHostViewMac::OnNSViewBoundsInWindowChanged(
     const gfx::Rect& view_bounds_in_window_dip,
     bool attached_to_window) {
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 4f8cd9b..882e27a 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -173,9 +173,8 @@
   }
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
-    client_->OnReceiveResponse(head, ssl_info, std::move(downloaded_file));
+    client_->OnReceiveResponse(head, std::move(downloaded_file));
     DCHECK(on_response_);
     std::move(on_response_).Run();
     AddDevToolsCallback(
diff --git a/content/browser/service_worker/service_worker_installed_script_loader.cc b/content/browser/service_worker/service_worker_installed_script_loader.cc
index 2b5d946..c1323dc4 100644
--- a/content/browser/service_worker/service_worker_installed_script_loader.cc
+++ b/content/browser/service_worker/service_worker_installed_script_loader.cc
@@ -78,11 +78,10 @@
   head.socket_address = info->socket_address;
   head.cert_status = info->ssl_info.cert_status;
 
-  base::Optional<net::SSLInfo> ssl_info;
   if (options_ & network::mojom::kURLLoadOptionSendSSLInfoWithResponse)
-    ssl_info = info->ssl_info;
+    head.ssl_info = info->ssl_info;
 
-  client_->OnReceiveResponse(head, ssl_info, nullptr /* downloaded_file */);
+  client_->OnReceiveResponse(head, nullptr /* downloaded_file */);
   client_->OnStartLoadingResponseBody(std::move(body_handle_));
   // We continue in OnFinished().
 }
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc
index 59ee781..9b7d5a88 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -198,7 +198,7 @@
   DCHECK_EQ(Status::kStarted, status_);
   DCHECK(url_loader_client_.is_bound());
   status_ = Status::kSentHeader;
-  url_loader_client_->OnReceiveResponse(response_head_, ssl_info_,
+  url_loader_client_->OnReceiveResponse(response_head_,
                                         nullptr /* downloaded_file */);
 }
 
@@ -301,6 +301,7 @@
   response_head_.did_service_worker_navigation_preload =
       did_navigation_preload_;
   response_head_.load_timing.receive_headers_end = base::TimeTicks::Now();
+  response_head_.ssl_info = ssl_info_;
 
   // Handle a redirect response. ComputeRedirectInfo returns non-null redirect
   // info if the given response is a redirect.
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
index 90b13ec..d2eee758 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -85,7 +85,6 @@
   // network::mojom::URLLoaderClient implementation
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     response_head_ = response_head;
   }
@@ -178,7 +177,7 @@
     network::ResourceResponseHead response;
     response.headers = info.headers;
     response.headers->GetMimeType(&response.mime_type);
-    client->OnReceiveResponse(response, base::nullopt, nullptr);
+    client->OnReceiveResponse(response, nullptr);
 
     std::string body = "this body came from the network";
     uint32_t bytes_written = body.size();
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc
index ede59ac..cc820508 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -132,7 +132,6 @@
 
 void ServiceWorkerNewScriptLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   if (!version_->context() || version_->is_redundant()) {
     CommitCompleted(network::URLLoaderCompletionStatus(net::ERR_FAILED));
@@ -143,8 +142,8 @@
   // At least we need headers and SSL info.
   auto response_info = std::make_unique<net::HttpResponseInfo>();
   response_info->headers = response_head.headers;
-  if (ssl_info.has_value())
-    response_info->ssl_info = *ssl_info;
+  if (response_head.ssl_info.has_value())
+    response_info->ssl_info = *response_head.ssl_info;
   response_info->was_fetched_via_spdy = response_head.was_fetched_via_spdy;
   response_info->was_alpn_negotiated = response_head.was_alpn_negotiated;
   response_info->alpn_negotiated_protocol =
@@ -206,8 +205,7 @@
   WriteHeaders(
       base::MakeRefCounted<HttpResponseInfoIOBuffer>(response_info.release()));
 
-  client_->OnReceiveResponse(response_head, ssl_info,
-                             std::move(downloaded_file));
+  client_->OnReceiveResponse(response_head, std::move(downloaded_file));
 }
 
 void ServiceWorkerNewScriptLoader::OnReceiveRedirect(
diff --git a/content/browser/service_worker/service_worker_new_script_loader.h b/content/browser/service_worker/service_worker_new_script_loader.h
index 994f2470..58e3211 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.h
+++ b/content/browser/service_worker/service_worker_new_script_loader.h
@@ -70,7 +70,6 @@
   // network::mojom::URLLoaderClient for the network load:
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
diff --git a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
index 5664ba19..16df871 100644
--- a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
@@ -99,8 +99,7 @@
       client->OnReceiveRedirect(net::RedirectInfo(), response_head);
       return;
     }
-    client->OnReceiveResponse(response_head, base::nullopt /* ssl_info */,
-                              nullptr /* downloaded_file */);
+    client->OnReceiveResponse(response_head, nullptr /* downloaded_file */);
 
     // Pass the response body to the client.
     uint32_t bytes_written = response.body.size();
diff --git a/content/browser/web_package/mock_signed_exchange_handler.cc b/content/browser/web_package/mock_signed_exchange_handler.cc
index 1708d7f..2381c3b9 100644
--- a/content/browser/web_package/mock_signed_exchange_handler.cc
+++ b/content/browser/web_package/mock_signed_exchange_handler.cc
@@ -32,7 +32,7 @@
   }
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(headers_callback), error, request_url,
-                                "GET", head, std::move(body), base::nullopt));
+                                "GET", head, std::move(body)));
 }
 
 MockSignedExchangeHandler::~MockSignedExchangeHandler() {}
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.cc b/content/browser/web_package/signed_exchange_cert_fetcher.cc
index 25d7c03..c88cae5 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.cc
@@ -260,7 +260,6 @@
 // network::mojom::URLLoaderClient
 void SignedExchangeCertFetcher::OnReceiveResponse(
     const network::ResourceResponseHead& head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
                      "SignedExchangeCertFetcher::OnReceiveResponse");
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.h b/content/browser/web_package/signed_exchange_cert_fetcher.h
index c6d96d2..19d8b85 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.h
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.h
@@ -88,7 +88,6 @@
   // network::mojom::URLLoaderClient
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override;
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
index 00efc6b6..2afbe71 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
@@ -221,8 +221,7 @@
         base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
 
     mock_loader_factory_.client_ptr()->OnReceiveResponse(
-        resource_response, base::Optional<net::SSLInfo>(),
-        nullptr /* downloaded_file */);
+        resource_response, nullptr /* downloaded_file */);
   }
 
   DeferringURLLoaderThrottle* InitializeDeferringURLLoaderThrottle() {
@@ -656,8 +655,7 @@
       base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
   resource_response.content_length = message.size();
   mock_loader_factory_.client_ptr()->OnReceiveResponse(
-      resource_response, base::Optional<net::SSLInfo>(),
-      nullptr /* downloaded_file */);
+      resource_response, nullptr /* downloaded_file */);
   mojo::DataPipe data_pipe(message.size());
   CHECK(
       mojo::common::BlockingCopyFromString(message, data_pipe.producer_handle));
@@ -692,8 +690,7 @@
   resource_response.headers =
       base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 404 Not Found");
   mock_loader_factory_.client_ptr()->OnReceiveResponse(
-      resource_response, base::Optional<net::SSLInfo>(),
-      nullptr /* downloaded_file */);
+      resource_response, nullptr /* downloaded_file */);
   RunUntilIdle();
 
   EXPECT_TRUE(callback_called_);
diff --git a/content/browser/web_package/signed_exchange_consts.h b/content/browser/web_package/signed_exchange_consts.h
index 409ecc11..a289b8d 100644
--- a/content/browser/web_package/signed_exchange_consts.h
+++ b/content/browser/web_package/signed_exchange_consts.h
@@ -10,18 +10,14 @@
 constexpr char kAcceptHeaderSignedExchangeSuffix[] =
     ",application/signed-exchange;v=b0";
 
-// Field names defined in the application/http-exchange+cbor content type:
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.5
+// Field names defined in the application/signed-exchange content type:
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#application-signed-exchange
 
 constexpr char kCertSha256Key[] = "certSha256";
 constexpr char kDateKey[] = "date";
 constexpr char kExpiresKey[] = "expires";
 constexpr char kHeadersKey[] = "headers";
-constexpr char kHtxg[] = "htxg";
 constexpr char kMethodKey[] = ":method";
-constexpr char kPayload[] = "payload";
-constexpr char kRequest[] = "request";
-constexpr char kResponse[] = "response";
 constexpr char kSignature[] = "signature";
 constexpr char kStatusKey[] = ":status";
 constexpr char kUrlKey[] = ":url";
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 32b8029..8ba3623c 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -22,6 +22,7 @@
 #include "net/filter/source_stream.h"
 #include "net/ssl/ssl_config.h"
 #include "net/ssl/ssl_config_service.h"
+#include "net/ssl/ssl_info.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
@@ -244,7 +245,7 @@
   DCHECK_NE(state_, State::kHeadersCallbackCalled);
   std::move(headers_callback_)
       .Run(error, GURL(), std::string(), network::ResourceResponseHead(),
-           nullptr, base::nullopt);
+           nullptr);
   state_ = State::kHeadersCallbackCalled;
 }
 
@@ -358,10 +359,11 @@
   ssl_info.is_fatal_cert_error =
       net::IsCertStatusError(ssl_info.cert_status) &&
       !net::IsCertStatusMinorError(ssl_info.cert_status);
+  response_head.ssl_info = std::move(ssl_info);
   // TODO(https://crbug.com/815025): Verify the Certificate Transparency status.
   std::move(headers_callback_)
       .Run(net::OK, header_->request_url(), header_->request_method(),
-           response_head, std::move(mi_stream), ssl_info);
+           response_head, std::move(mi_stream));
   state_ = State::kHeadersCallbackCalled;
   TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("loading"),
                    "SignedExchangeHandler::OnCertVerifyComplete");
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h
index a0007d2..a01bc811 100644
--- a/content/browser/web_package/signed_exchange_handler.h
+++ b/content/browser/web_package/signed_exchange_handler.h
@@ -17,7 +17,6 @@
 #include "net/cert/cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/log/net_log_with_source.h"
-#include "net/ssl/ssl_info.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -46,13 +45,12 @@
 class CONTENT_EXPORT SignedExchangeHandler {
  public:
   // TODO(https://crbug.com/803774): Add verification status here.
-  using ExchangeHeadersCallback =
-      base::OnceCallback<void(net::Error error,
-                              const GURL& request_url,
-                              const std::string& request_method,
-                              const network::ResourceResponseHead&,
-                              std::unique_ptr<net::SourceStream> payload_stream,
-                              base::Optional<net::SSLInfo>)>;
+  using ExchangeHeadersCallback = base::OnceCallback<void(
+      net::Error error,
+      const GURL& request_url,
+      const std::string& request_method,
+      const network::ResourceResponseHead&,
+      std::unique_ptr<net::SourceStream> payload_stream)>;
 
   // TODO(https://crbug.com/817187): Find a more sophisticated way to use a
   // MockCertVerifier in browser tests instead of using the static method.
diff --git a/content/browser/web_package/signed_exchange_handler_unittest.cc b/content/browser/web_package/signed_exchange_handler_unittest.cc
index 9ec506f..a13819c 100644
--- a/content/browser/web_package/signed_exchange_handler_unittest.cc
+++ b/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -177,8 +177,7 @@
                      const GURL&,
                      const std::string&,
                      const network::ResourceResponseHead& resource_response,
-                     std::unique_ptr<net::SourceStream> payload_stream,
-                     base::Optional<net::SSLInfo>) {
+                     std::unique_ptr<net::SourceStream> payload_stream) {
     read_header_ = true;
     error_ = error;
     resource_response_ = resource_response;
diff --git a/content/browser/web_package/signed_exchange_header.cc b/content/browser/web_package/signed_exchange_header.cc
index 94b2008d..e44602f 100644
--- a/content/browser/web_package/signed_exchange_header.cc
+++ b/content/browser/web_package/signed_exchange_header.cc
@@ -21,7 +21,7 @@
 // header field. Stateful header fields will cause validation failure of
 // signed exchanges.
 // Note that |name| must be lower-cased.
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.4.1
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#stateful-headers
 bool IsStatefulRequestHeader(base::StringPiece name) {
   DCHECK_EQ(name, base::ToLowerASCII(name));
 
diff --git a/content/browser/web_package/signed_exchange_header.h b/content/browser/web_package/signed_exchange_header.h
index 1e608fb..57132d9 100644
--- a/content/browser/web_package/signed_exchange_header.h
+++ b/content/browser/web_package/signed_exchange_header.h
@@ -22,7 +22,7 @@
 
 // SignedExchangeHeader contains all information captured in signed exchange
 // envelope but the payload.
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html
 class CONTENT_EXPORT SignedExchangeHeader {
  public:
   static constexpr size_t kEncodedHeaderLengthInBytes = 3;
@@ -35,10 +35,10 @@
   using HeaderMap = std::map<std::string, std::string>;
 
   // Parse headers from the application/signed-exchange;v=b0 format.
-  // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#rfc.section.5.3
+  // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#application-signed-exchange
   //
   // This also performs the step 3 and 4 of "Cross-origin trust" validation.
-  // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.4
+  // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-trust
   static base::Optional<SignedExchangeHeader> Parse(
       base::span<const uint8_t> input);
   SignedExchangeHeader();
diff --git a/content/browser/web_package/signed_exchange_header_parser.h b/content/browser/web_package/signed_exchange_header_parser.h
index 4e25188b..1221972c 100644
--- a/content/browser/web_package/signed_exchange_header_parser.h
+++ b/content/browser/web_package/signed_exchange_header_parser.h
@@ -19,7 +19,7 @@
 namespace content {
 
 // Provide parsers for signed-exchange headers.
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html
 class CONTENT_EXPORT SignedExchangeHeaderParser {
  public:
   struct CONTENT_EXPORT Signature {
@@ -40,7 +40,7 @@
   };
 
   // Parses a value of the Signature header.
-  // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.2
+  // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-header
   static base::Optional<std::vector<Signature>> ParseSignature(
       base::StringPiece signature_str);
 
diff --git a/content/browser/web_package/signed_exchange_signature_verifier.cc b/content/browser/web_package/signed_exchange_signature_verifier.cc
index d400e49..7dfb536 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier.cc
@@ -24,18 +24,18 @@
 
 namespace {
 
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.6
-// Step 11. "Let message be the concatenation of the following byte strings."
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
+// Step 7. "Let message be the concatenation of the following byte strings."
 constexpr uint8_t kMessageHeader[] =
-    // 11.1. "A string that consists of octet 32 (0x20) repeated 64 times."
+    // 7.1. "A string that consists of octet 32 (0x20) repeated 64 times."
     // [spec text]
     "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
     "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
     "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
     "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
-    // 11.2. "A context string: the ASCII encoding of "HTTP Exchange"."
+    // 7.2. "A context string: the ASCII encoding of "HTTP Exchange"."
     // [spec text]
-    // 11.3. "A single 0 byte which serves as a separator." [spec text]
+    // 7.3. "A single 0 byte which serves as a separator." [spec text]
     "HTTP Exchange";
 
 base::Optional<cbor::CBORValue> GenerateCanonicalRequestCBOR(
@@ -72,7 +72,7 @@
 }
 
 // Generate CBORValue from |header| as specified in:
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.4
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cbor-representation
 base::Optional<cbor::CBORValue> GenerateCanonicalExchangeHeadersCBOR(
     const SignedExchangeHeader& header) {
   auto req_val = GenerateCanonicalRequestCBOR(header);
@@ -89,18 +89,18 @@
 }
 
 // Generate a CBOR map value as specified in
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.6
-// Step 11.4.
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
+// Step 7.4.
 base::Optional<cbor::CBORValue> GenerateSignedMessageCBOR(
     const SignedExchangeHeader& header) {
   auto headers_val = GenerateCanonicalExchangeHeadersCBOR(header);
   if (!headers_val)
     return base::nullopt;
 
-  // 11.4. "The bytes of the canonical CBOR serialization (Section 3.5) of
+  // 7.4. "The bytes of the canonical CBOR serialization (Section 3.4) of
   // a CBOR map mapping:" [spec text]
   cbor::CBORValue::MapValue map;
-  // 11.4.1. "If certSha256 is set: The text string "certSha256" to the byte
+  // 7.4.1. "If certSha256 is set: The text string "certSha256" to the byte
   // string value of certSha256." [spec text]
   if (header.signature().cert_sha256.has_value()) {
     map.insert_or_assign(
@@ -111,19 +111,19 @@
                               sizeof(header.signature().cert_sha256->data)),
             cbor::CBORValue::Type::BYTE_STRING));
   }
-  // 11.4.2. "The text string "validityUrl" to the byte string value of
+  // 7.4.2. "The text string "validityUrl" to the byte string value of
   // validityUrl." [spec text]
   map.insert_or_assign(cbor::CBORValue(kValidityUrlKey),
                        cbor::CBORValue(header.signature().validity_url.spec(),
                                        cbor::CBORValue::Type::BYTE_STRING));
-  // 11.4.3. "The text string "date" to the integer value of date." [spec text]
+  // 7.4.3. "The text string "date" to the integer value of date." [spec text]
   if (!base::IsValueInRangeForNumericType<int64_t>(header.signature().date))
     return base::nullopt;
 
   map.insert_or_assign(
       cbor::CBORValue(kDateKey),
       cbor::CBORValue(base::checked_cast<int64_t>(header.signature().date)));
-  // 11.4.4. "The text string "expires" to the integer value of expires."
+  // 7.4.4. "The text string "expires" to the integer value of expires."
   // [spec text]
   if (!base::IsValueInRangeForNumericType<int64_t>(header.signature().expires))
     return base::nullopt;
@@ -131,8 +131,8 @@
   map.insert_or_assign(
       cbor::CBORValue(kExpiresKey),
       cbor::CBORValue(base::checked_cast<int64_t>(header.signature().expires)));
-  // 11.4.5. "The text string "headers" to the CBOR representation
-  // (Section 3.4) of exchange's headers." [spec text]
+  // 7.4.5. "The text string "headers" to the CBOR representation
+  // (Section 3.2) of exchange's headers." [spec text]
   map.insert_or_assign(cbor::CBORValue(kHeadersKey), std::move(*headers_val));
   return cbor::CBORValue(map);
 }
@@ -195,7 +195,7 @@
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
                      "GenerateSignedMessage");
 
-  // GenerateSignedMessageCBOR corresponds to Step 11.4.
+  // GenerateSignedMessageCBOR corresponds to Step 7.4.
   base::Optional<cbor::CBORValue> cbor_val = GenerateSignedMessageCBOR(header);
   if (!cbor_val) {
     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("loading"),
@@ -213,15 +213,15 @@
     return base::nullopt;
   }
 
-  // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.6
-  // Step 11. "Let message be the concatenation of the following byte strings."
+  // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
+  // Step 7. "Let message be the concatenation of the following byte strings."
   std::vector<uint8_t> message;
-  // see kMessageHeader for Steps 11.1 to 11.3.
+  // see kMessageHeader for Steps 7.1 to 7.3.
   message.reserve(arraysize(kMessageHeader) + cbor_message->size());
   message.insert(message.end(), std::begin(kMessageHeader),
                  std::end(kMessageHeader));
-  // 11.4. "The text string “headers” to the CBOR representation (Section 3.4)
-  // of exchange’s headers." [spec text]
+  // 7.4. "The bytes of the canonical CBOR serialization (Section 3.4) of
+  // a CBOR map mapping:" [spec text]
   message.insert(message.end(), cbor_message->begin(), cbor_message->end());
   TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("loading"),
                    "GenerateSignedMessage", "dump", HexDump(message));
@@ -232,8 +232,8 @@
   return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(t);
 }
 
-// Implements steps 9-10 of
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.6
+// Implements steps 5-6 of
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
 bool VerifyTimestamps(const SignedExchangeHeader& header,
                       const base::Time& verification_time) {
   base::Time expires_time =
@@ -241,12 +241,12 @@
   base::Time creation_time =
       TimeFromSignedExchangeUnixTime(header.signature().date);
 
-  // 9. "If expires is more than 7 days (604800 seconds) after date, return
+  // 5. "If expires is more than 7 days (604800 seconds) after date, return
   // "invalid"." [spec text]
   if ((expires_time - creation_time).InSeconds() > 604800)
     return false;
 
-  // 10. "If the current time is before date or after expires, return
+  // 6. "If the current time is before date or after expires, return
   // "invalid"."
   if (verification_time < creation_time || expires_time < verification_time)
     return false;
diff --git a/content/browser/web_package/signed_exchange_signature_verifier.h b/content/browser/web_package/signed_exchange_signature_verifier.h
index b60c0bb..11c861f 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier.h
+++ b/content/browser/web_package/signed_exchange_signature_verifier.h
@@ -31,7 +31,7 @@
 // of the certificate used to generate the signature, which can't be done
 // synchronously. (See SignedExchangeCertFetcher for this logic.)
 //
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.6
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
 class CONTENT_EXPORT SignedExchangeSignatureVerifier final {
  public:
   enum class Result {
diff --git a/content/browser/web_package/web_package_loader.cc b/content/browser/web_package/web_package_loader.cc
index c102cc3..d39b4676 100644
--- a/content/browser/web_package/web_package_loader.cc
+++ b/content/browser/web_package/web_package_loader.cc
@@ -123,7 +123,6 @@
 
 void WebPackageLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   // Must not be called because this WebPackageLoader and the client endpoints
   // were bound after OnReceiveResponse() is called.
@@ -229,8 +228,7 @@
     const GURL& request_url,
     const std::string& request_method,
     const network::ResourceResponseHead& resource_response,
-    std::unique_ptr<net::SourceStream> payload_stream,
-    base::Optional<net::SSLInfo> ssl_info) {
+    std::unique_ptr<net::SourceStream> payload_stream) {
   if (error) {
     // This will eventually delete |this|.
     forwarding_client_->OnComplete(network::URLLoaderCompletionStatus(error));
@@ -244,19 +242,24 @@
       std::move(original_response_timing_info_)->CreateRedirectResponseHead());
   forwarding_client_.reset();
 
-  if (ssl_info &&
+  const base::Optional<net::SSLInfo>& ssl_info = resource_response.ssl_info;
+  if (ssl_info.has_value() &&
       (url_loader_options_ &
        network::mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
       net::IsCertStatusError(ssl_info->cert_status) &&
       !net::IsCertStatusMinorError(ssl_info->cert_status)) {
     ssl_info_ = ssl_info;
   }
-  if (!(url_loader_options_ &
+  if (ssl_info.has_value() &&
+      !(url_loader_options_ &
         network::mojom::kURLLoadOptionSendSSLInfoWithResponse)) {
-    ssl_info = base::nullopt;
+    network::ResourceResponseHead response_info = resource_response;
+    response_info.ssl_info = base::nullopt;
+    client_->OnReceiveResponse(response_info, nullptr /* downloaded_file */);
+  } else {
+    client_->OnReceiveResponse(resource_response,
+                               nullptr /* downloaded_file */);
   }
-  client_->OnReceiveResponse(resource_response, std::move(ssl_info),
-                             nullptr /* downloaded_file */);
 
   // Currently we always assume that we have body.
   // TODO(https://crbug.com/80374): Add error handling and bail out
diff --git a/content/browser/web_package/web_package_loader.h b/content/browser/web_package/web_package_loader.h
index 2df683f..c01d5da 100644
--- a/content/browser/web_package/web_package_loader.h
+++ b/content/browser/web_package/web_package_loader.h
@@ -57,7 +57,6 @@
   // Only OnStartLoadingResponseBody() and OnComplete() are called.
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
@@ -96,8 +95,7 @@
       const GURL& request_url,
       const std::string& request_method,
       const network::ResourceResponseHead& resource_response,
-      std::unique_ptr<net::SourceStream> payload_stream,
-      base::Optional<net::SSLInfo> ssl_info);
+      std::unique_ptr<net::SourceStream> payload_stream);
 
   void FinishReadingBody(int result);
 
diff --git a/content/browser/web_package/web_package_prefetch_handler.cc b/content/browser/web_package/web_package_prefetch_handler.cc
index a8cddcf..e4a652d 100644
--- a/content/browser/web_package/web_package_prefetch_handler.cc
+++ b/content/browser/web_package/web_package_prefetch_handler.cc
@@ -76,7 +76,6 @@
 
 void WebPackagePrefetchHandler::OnReceiveResponse(
     const network::ResourceResponseHead& head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   NOTREACHED();
 }
diff --git a/content/browser/web_package/web_package_prefetch_handler.h b/content/browser/web_package/web_package_prefetch_handler.h
index 9d8d617..581b7024 100644
--- a/content/browser/web_package/web_package_prefetch_handler.h
+++ b/content/browser/web_package/web_package_prefetch_handler.h
@@ -61,7 +61,6 @@
   // network::mojom::URLLoaderClient overrides:
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const network::ResourceResponseHead& head) override;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 334072a1..4b51c48 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/json/json_writer.h"
 #include "base/run_loop.h"
 #include "base/test/gtest_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
@@ -23,6 +24,7 @@
 #include "content/test/test_render_frame_host.h"
 #include "device/fido/fake_hid_impl_for_testing.h"
 #include "device/fido/scoped_virtual_fido_device.h"
+#include "device/fido/test_callback_receiver.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/device/public/mojom/constants.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -167,6 +169,13 @@
     {"https://login.awesomecompany", "awesomecompany"},
 };
 
+using TestMakeCredentialCallback = device::test::StatusAndValueCallbackReceiver<
+    AuthenticatorStatus,
+    MakeCredentialAuthenticatorResponsePtr>;
+using TestGetAssertionCallback = device::test::StatusAndValueCallbackReceiver<
+    AuthenticatorStatus,
+    GetAssertionAuthenticatorResponsePtr>;
+
 std::vector<uint8_t> GetTestChallengeBytes() {
   return std::vector<uint8_t>(std::begin(kTestChallengeBytes),
                               std::end(kTestChallengeBytes));
@@ -233,77 +242,6 @@
   return options;
 }
 
-class TestMakeCredentialCallback {
- public:
-  TestMakeCredentialCallback()
-      : callback_(base::BindOnce(&TestMakeCredentialCallback::ReceivedCallback,
-                                 base::Unretained(this))) {}
-  ~TestMakeCredentialCallback() {}
-
-  void ReceivedCallback(AuthenticatorStatus status,
-                        MakeCredentialAuthenticatorResponsePtr credential) {
-    response_ = std::make_pair(status, std::move(credential));
-    std::move(closure_).Run();
-  }
-
-  // TODO(crbug.com/799044) - simplify the runloop usage.
-  void WaitForCallback() {
-    closure_ = run_loop_.QuitClosure();
-    run_loop_.Run();
-  }
-
-  AuthenticatorImpl::MakeCredentialCallback callback() {
-    return std::move(callback_);
-  }
-
-  AuthenticatorStatus GetResponseStatus() { return response_.first; }
-
-  const MakeCredentialAuthenticatorResponsePtr& response() const {
-    CHECK_EQ(AuthenticatorStatus::SUCCESS, response_.first);
-    return response_.second;
-  }
-
- private:
-  std::pair<AuthenticatorStatus, MakeCredentialAuthenticatorResponsePtr>
-      response_;
-  base::Closure closure_;
-  AuthenticatorImpl::MakeCredentialCallback callback_;
-  base::RunLoop run_loop_;
-};
-
-class TestGetAssertionCallback {
- public:
-  TestGetAssertionCallback()
-      : callback_(base::BindOnce(&TestGetAssertionCallback::ReceivedCallback,
-                                 base::Unretained(this))) {}
-  ~TestGetAssertionCallback() {}
-
-  void ReceivedCallback(AuthenticatorStatus status,
-                        GetAssertionAuthenticatorResponsePtr credential) {
-    response_ = std::make_pair(status, std::move(credential));
-    std::move(closure_).Run();
-  }
-
-  // TODO(crbug.com/799044) - simplify the runloop usage.
-  void WaitForCallback() {
-    closure_ = run_loop_.QuitClosure();
-    run_loop_.Run();
-  }
-
-  AuthenticatorStatus GetResponseStatus() { return response_.first; }
-
-  AuthenticatorImpl::GetAssertionCallback callback() {
-    return std::move(callback_);
-  }
-
- private:
-  std::pair<AuthenticatorStatus, GetAssertionAuthenticatorResponsePtr>
-      response_;
-  base::OnceClosure closure_;
-  AuthenticatorImpl::GetAssertionCallback callback_;
-  base::RunLoop run_loop_;
-};
-
 }  // namespace
 
 class AuthenticatorImplTest : public content::RenderViewHostTestHarness {
@@ -375,7 +313,7 @@
     TestMakeCredentialCallback cb;
     authenticator->MakeCredential(std::move(options), cb.callback());
     cb.WaitForCallback();
-    EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, cb.GetResponseStatus());
+    EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, cb.status());
   }
 
   // These instances pass the origin and relying party checks and return at
@@ -394,7 +332,7 @@
     TestMakeCredentialCallback cb;
     authenticator->MakeCredential(std::move(options), cb.callback());
     cb.WaitForCallback();
-    EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.GetResponseStatus());
+    EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.status());
   }
 }
 
@@ -411,7 +349,7 @@
   TestMakeCredentialCallback cb;
   authenticator->MakeCredential(std::move(options), cb.callback());
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.status());
 }
 
 // Test that service returns NOT_SUPPORTED_ERROR if user verification is
@@ -427,7 +365,7 @@
   TestGetAssertionCallback cb;
   authenticator->GetAssertion(std::move(options), cb.callback());
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.status());
 }
 
 // Test that service returns NOT_SUPPORTED_ERROR if user verification is
@@ -444,7 +382,7 @@
   TestMakeCredentialCallback cb;
   authenticator->MakeCredential(std::move(options), cb.callback());
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.status());
 }
 
 // Test that service returns NOT_SUPPORTED_ERROR if resident key is
@@ -460,7 +398,7 @@
   TestMakeCredentialCallback cb;
   authenticator->MakeCredential(std::move(options), cb.callback());
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_SUPPORTED_ERROR, cb.status());
 }
 
 // Parses its arguments as JSON and expects that all the keys in the first are
@@ -557,7 +495,7 @@
   base::RunLoop().RunUntilIdle();
   task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.status());
 }
 
 // Verify behavior for various combinations of origins and RP IDs.
@@ -578,7 +516,7 @@
     TestGetAssertionCallback cb;
     authenticator->GetAssertion(std::move(options), cb.callback());
     cb.WaitForCallback();
-    EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, cb.GetResponseStatus());
+    EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, cb.status());
   }
 }
 
@@ -631,10 +569,11 @@
     authenticator->GetAssertion(std::move(options), cb.callback());
     cb.WaitForCallback();
 
+    const AuthenticatorStatus status = cb.status();
     if (test_case.should_succeed) {
-      EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.GetResponseStatus());
+      EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, status);
     } else {
-      EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, cb.GetResponseStatus());
+      EXPECT_EQ(AuthenticatorStatus::INVALID_DOMAIN, status);
     }
   }
 
@@ -673,7 +612,7 @@
   base::RunLoop().RunUntilIdle();
   task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
   cb.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.GetResponseStatus());
+  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.status());
 }
 
 enum class IndividualAttestation {
@@ -763,7 +702,7 @@
       TestMakeCredentialCallback cb;
       authenticator->MakeCredential(std::move(options), cb.callback());
       cb.WaitForCallback();
-      ASSERT_EQ(test.expected_status, cb.GetResponseStatus());
+      ASSERT_EQ(test.expected_status, cb.status());
 
       if (test.expected_status != AuthenticatorStatus::SUCCESS) {
         ASSERT_STREQ("", test.expected_attestation_format);
@@ -771,7 +710,7 @@
       }
 
       base::Optional<CBORValue> attestation_value =
-          CBORReader::Read(cb.response()->attestation_object);
+          CBORReader::Read(cb.value()->attestation_object);
       ASSERT_TRUE(attestation_value);
       ASSERT_TRUE(attestation_value->is_map());
       const auto& attestation = attestation_value->GetMap();
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index d6e4728c..fb7a2fe 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -66,7 +66,7 @@
 
   network::mojom::URLLoaderClientPtr client;
   client.Bind(std::move(client_info));
-  client->OnReceiveResponse(headers->head, base::nullopt, nullptr);
+  client->OnReceiveResponse(headers->head, nullptr);
 
   base::StringPiece input(reinterpret_cast<const char*>(bytes->front()),
                           bytes->size());
diff --git a/content/common/content_param_traits.cc b/content/common/content_param_traits.cc
index 038d4fc..cc3eea2f 100644
--- a/content/common/content_param_traits.cc
+++ b/content/common/content_param_traits.cc
@@ -198,7 +198,7 @@
 void ParamTraits<scoped_refptr<base::RefCountedData<
     blink::TransferableMessage>>>::Write(base::Pickle* m, const param_type& p) {
   m->WriteData(reinterpret_cast<const char*>(p->data.encoded_message.data()),
-               p->data.encoded_message.length());
+               p->data.encoded_message.size());
   WriteParam(m, p->data.blobs);
   WriteParam(m, p->data.stack_trace_id);
   WriteParam(m, p->data.stack_trace_debugger_id_first);
diff --git a/content/common/throttling_url_loader.cc b/content/common/throttling_url_loader.cc
index f14adc53..eda2505e 100644
--- a/content/common/throttling_url_loader.cc
+++ b/content/common/throttling_url_loader.cc
@@ -126,10 +126,8 @@
 
 ThrottlingURLLoader::ResponseInfo::ResponseInfo(
     const network::ResourceResponseHead& in_response_head,
-    const base::Optional<net::SSLInfo>& in_ssl_info,
     network::mojom::DownloadedTempFilePtr in_downloaded_file)
     : response_head(in_response_head),
-      ssl_info(in_ssl_info),
       downloaded_file(std::move(in_downloaded_file)) {}
 
 ThrottlingURLLoader::ResponseInfo::~ResponseInfo() = default;
@@ -310,7 +308,6 @@
 
 void ThrottlingURLLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
   DCHECK(!loader_cancelled_);
@@ -330,13 +327,13 @@
     if (deferred) {
       deferred_stage_ = DEFERRED_RESPONSE;
       response_info_ = std::make_unique<ResponseInfo>(
-          response_head, ssl_info, std::move(downloaded_file));
+          response_head, std::move(downloaded_file));
       client_binding_.PauseIncomingMethodCallProcessing();
       return;
     }
   }
 
-  forwarding_client_->OnReceiveResponse(response_head, ssl_info,
+  forwarding_client_->OnReceiveResponse(response_head,
                                         std::move(downloaded_file));
 }
 
@@ -479,7 +476,7 @@
     case DEFERRED_RESPONSE: {
       client_binding_.ResumeIncomingMethodCallProcessing();
       forwarding_client_->OnReceiveResponse(
-          response_info_->response_head, response_info_->ssl_info,
+          response_info_->response_head,
           std::move(response_info_->downloaded_file));
       break;
     }
diff --git a/content/common/throttling_url_loader.h b/content/common/throttling_url_loader.h
index b81bc99..af9f50eb 100644
--- a/content/common/throttling_url_loader.h
+++ b/content/common/throttling_url_loader.h
@@ -102,7 +102,6 @@
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
@@ -194,12 +193,10 @@
 
   struct ResponseInfo {
     ResponseInfo(const network::ResourceResponseHead& in_response_head,
-                 const base::Optional<net::SSLInfo>& in_ssl_info,
                  network::mojom::DownloadedTempFilePtr in_downloaded_file);
     ~ResponseInfo();
 
     network::ResourceResponseHead response_head;
-    base::Optional<net::SSLInfo> ssl_info;
     network::mojom::DownloadedTempFilePtr downloaded_file;
   };
   // Set if response is deferred.
diff --git a/content/common/throttling_url_loader_unittest.cc b/content/common/throttling_url_loader_unittest.cc
index fcb14cc..931aaa2 100644
--- a/content/common/throttling_url_loader_unittest.cc
+++ b/content/common/throttling_url_loader_unittest.cc
@@ -54,8 +54,7 @@
   }
 
   void NotifyClientOnReceiveResponse() {
-    client_ptr_->OnReceiveResponse(network::ResourceResponseHead(),
-                                   base::nullopt, nullptr);
+    client_ptr_->OnReceiveResponse(network::ResourceResponseHead(), nullptr);
   }
 
   void NotifyClientOnReceiveRedirect() {
@@ -148,7 +147,6 @@
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     on_received_response_called_++;
     if (on_received_response_callback_)
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index 6d42fe6..5f0ae2d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -377,21 +377,6 @@
         return nativeGetTopControlsShrinkBlinkHeightPixForTesting(mNativeContentViewCore);
     }
 
-    @Override
-    public void onShow() {
-        assert mWebContents != null;
-        mWebContents.onShow();
-        getWebContentsAccessibility().refreshState();
-        getSelectionPopupController().restoreSelectionPopupsIfNecessary();
-    }
-
-    @Override
-    public void onHide() {
-        assert mWebContents != null;
-        hidePopupsAndPreserveSelection();
-        mWebContents.onHide();
-    }
-
     private void hidePopupsAndClearSelection() {
         getSelectionPopupController().destroyActionModeAndUnselect();
         mWebContents.dismissTextHandles();
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
index 643d2ce..894c9e1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
@@ -15,15 +15,14 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.content_public.browser.ContentViewCore;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
 /***
  * This view is used by a ContentView to render its content.
- * Call {@link #setCurrentContentViewCore(ContentViewCore)} with the contentViewCore that should be
- * managing the view.
- * Note that only one ContentViewCore can be shown at a time.
+ * Call {@link #setCurrentWebContents(WebContents)} with the webContents that should be
+ * managing the content.
+ * Note that only one WebContents can be shown at a time.
  */
 @JNINamespace("content")
 public class ContentViewRenderView extends FrameLayout {
@@ -33,7 +32,7 @@
     private WindowAndroid mWindowAndroid;
 
     private final SurfaceView mSurfaceView;
-    protected ContentViewCore mContentViewCore;
+    protected WebContents mWebContents;
 
     private int mWidth;
     private int mHeight;
@@ -77,9 +76,9 @@
                 assert mNativeContentViewRenderView != 0;
                 nativeSurfaceChanged(mNativeContentViewRenderView,
                         format, width, height, holder.getSurface());
-                if (mContentViewCore != null) {
-                    nativeOnPhysicalBackingSizeChanged(mNativeContentViewRenderView,
-                            mContentViewCore.getWebContents(), width, height);
+                if (mWebContents != null) {
+                    nativeOnPhysicalBackingSizeChanged(
+                            mNativeContentViewRenderView, mWebContents, width, height);
                 }
             }
 
@@ -112,9 +111,7 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         mWidth = w;
         mHeight = h;
-        WebContents webContents =
-                mContentViewCore != null ? mContentViewCore.getWebContents() : null;
-        if (webContents != null) webContents.setSize(w, h);
+        if (mWebContents != null) mWebContents.setSize(w, h);
     }
 
     /**
@@ -163,11 +160,10 @@
         mNativeContentViewRenderView = 0;
     }
 
-    public void setCurrentContentViewCore(ContentViewCore contentViewCore) {
+    public void setCurrentWebContents(WebContents webContents) {
         assert mNativeContentViewRenderView != 0;
-        mContentViewCore = contentViewCore;
+        mWebContents = webContents;
 
-        WebContents webContents = contentViewCore != null ? contentViewCore.getWebContents() : null;
         if (webContents != null) {
             webContents.setSize(mWidth, mHeight);
             nativeOnPhysicalBackingSizeChanged(
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index c6f1099..cd43a0d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -40,6 +40,7 @@
 import org.chromium.blink_public.web.WebTextInputMode;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.picker.InputDialogContainer;
+import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content.browser.webcontents.WebContentsUserData;
 import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ImeAdapter;
@@ -99,7 +100,7 @@
     // ResultReceiver in the InputMethodService (IME app) gets gc'ed.
     private ShowKeyboardResultReceiver mShowKeyboardResultReceiver;
 
-    private final WebContents mWebContents;
+    private final WebContentsImpl mWebContents;
     private View mContainerView;
 
     // This holds the information necessary for constructing CursorAnchorInfo, and notifies to
@@ -207,7 +208,7 @@
      * @param webContents WebContents instance.
      */
     public ImeAdapterImpl(WebContents webContents) {
-        mWebContents = webContents;
+        mWebContents = (WebContentsImpl) webContents;
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
index 8fa8325..9ea04b1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
@@ -42,7 +42,7 @@
         public void hide(boolean sendsCancelMessage);
     }
 
-    private final WebContents mWebContents;
+    private final WebContentsImpl mWebContents;
     private Context mContext;
     private View mContainerView;
     private Ui mPopupView;
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 4e1a321..e843a7a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -23,8 +23,10 @@
 import org.chromium.content.browser.AppWebMessagePort;
 import org.chromium.content.browser.MediaSessionImpl;
 import org.chromium.content.browser.RenderCoordinates;
+import org.chromium.content.browser.accessibility.WebContentsAccessibilityImpl;
 import org.chromium.content.browser.framehost.RenderFrameHostDelegate;
 import org.chromium.content.browser.framehost.RenderFrameHostImpl;
+import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.ChildProcessImportance;
@@ -303,37 +305,51 @@
         nativeStop(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Cut the selected content.
+     */
     public void cut() {
         nativeCut(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Copy the selected content.
+     */
     public void copy() {
         nativeCopy(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Paste content from the clipboard.
+     */
     public void paste() {
         nativePaste(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Paste content from the clipboard without format.
+     */
     public void pasteAsPlainText() {
         nativePasteAsPlainText(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Replace the selected text with the {@code word}.
+     */
     public void replace(String word) {
         nativeReplace(mNativeWebContentsAndroid, word);
     }
 
-    @Override
+    /**
+     * Select all content.
+     */
     public void selectAll() {
         nativeSelectAll(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Collapse the selection to the end of selection range.
+     */
     public void collapseSelection() {
         // collapseSelection may get triggered when certain selection-related widgets
         // are destroyed. As the timing for such destruction is unpredictable,
@@ -344,14 +360,24 @@
 
     @Override
     public void onHide() {
+        SelectionPopupControllerImpl controller = getSelectionPopupController();
+        if (controller != null) controller.hidePopupsAndPreserveSelection();
         nativeOnHide(mNativeWebContentsAndroid);
     }
 
     @Override
     public void onShow() {
+        WebContentsAccessibilityImpl wcax = WebContentsAccessibilityImpl.fromWebContents(this);
+        if (wcax != null) wcax.refreshState();
+        SelectionPopupControllerImpl controller = getSelectionPopupController();
+        if (controller != null) controller.restoreSelectionPopupsIfNecessary();
         nativeOnShow(mNativeWebContentsAndroid);
     }
 
+    private SelectionPopupControllerImpl getSelectionPopupController() {
+        return SelectionPopupControllerImpl.fromWebContents(this);
+    }
+
     @Override
     public void setImportance(@ChildProcessImportance int importance) {
         nativeSetImportance(mNativeWebContentsAndroid, importance);
@@ -622,12 +648,16 @@
         callback.onFinishDownloadImage(id, httpStatusCode, imageUrl, bitmaps, sizes);
     }
 
-    @Override
+    /**
+     * Removes handles used in text selection.
+     */
     public void dismissTextHandles() {
         nativeDismissTextHandles(mNativeWebContentsAndroid);
     }
 
-    @Override
+    /**
+     * Shows paste popup menu at the touch handle at specified location.
+     */
     public void showContextMenuAtTouchHandle(int x, int y) {
         nativeShowContextMenuAtTouchHandle(mNativeWebContentsAndroid, x, y);
     }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
index a74f242..9e92759c 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
@@ -150,16 +150,6 @@
     boolean isAlive();
 
     /**
-     * To be called when the ContentView is shown.
-     */
-    void onShow();
-
-    /**
-     * To be called when the ContentView is hidden.
-     */
-    void onHide();
-
-    /**
      * @see View#onAttachedToWindow()
      */
     void onAttachedToWindow();
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 86434c2..00fd5838 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -123,48 +123,6 @@
      */
     void stop();
 
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Cut the selected content.
-     */
-    void cut();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Copy the selected content.
-     */
-    void copy();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Paste content from the clipboard.
-     */
-    void paste();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Paste content from the clipboard without format.
-     */
-    void pasteAsPlainText();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Replace the selected text with the {@code word}.
-     */
-    void replace(String word);
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Select all content.
-     */
-    void selectAll();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Collapse the selection to the end of selection range.
-     */
-    void collapseSelection();
-
     /**
      * To be called when the ContentView is hidden.
      */
@@ -181,18 +139,6 @@
      */
     void setImportance(@ChildProcessImportance int importance);
 
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Removes handles used in text selection.
-     */
-    void dismissTextHandles();
-
-    // TODO (amaralp): Only used in content. Should be moved out of public interface.
-    /**
-     * Shows paste popup menu at the touch handle at specified location.
-     */
-    void showContextMenuAtTouchHandle(int x, int y);
-
     /**
      * Suspends all media players for this WebContents.  Note: There may still
      * be activities generating audio, so setAudioMuted() should also be called
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
index bc5eb81df9..c287a3a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
@@ -23,7 +23,7 @@
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.WebContents;
+import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule.RerunWithUpdatedContainerView;
 
@@ -78,7 +78,8 @@
         clipboardManager.setPrimaryClip(ClipData.newPlainText(null, ""));
         Assert.assertFalse(hasPrimaryClip(clipboardManager));
 
-        final WebContents webContents = mActivityTestRule.getContentViewCore().getWebContents();
+        final WebContentsImpl webContents =
+                (WebContentsImpl) mActivityTestRule.getContentViewCore().getWebContents();
         selectAll(webContents);
         copy(webContents);
 
@@ -106,7 +107,7 @@
         });
     }
 
-    private void copy(final WebContents webContents) {
+    private void copy(final WebContentsImpl webContents) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -115,7 +116,7 @@
         });
     }
 
-    private void selectAll(final WebContents webContents) {
+    private void selectAll(final WebContentsImpl webContents) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index edbfe55..877da992 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -33,6 +33,7 @@
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.SelectionClient;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.util.concurrent.Callable;
@@ -107,7 +108,7 @@
 
         mContentViewCore = mActivityTestRule.getContentViewCore();
         mSelectionPopupController =
-                SelectionPopupControllerImpl.fromWebContents(mContentViewCore.getWebContents());
+                SelectionPopupControllerImpl.fromWebContents(mActivityTestRule.getWebContents());
         waitForSelectActionBarVisible(false);
         waitForPastePopupStatus(false);
     }
@@ -635,7 +636,7 @@
     private CharSequence getTextBeforeCursor(final int length, final int flags) {
         final ChromiumBaseInputConnection connection =
                 (ChromiumBaseInputConnection) ImeAdapter
-                        .fromWebContents(mContentViewCore.getWebContents())
+                        .fromWebContents(mActivityTestRule.getWebContents())
                         .getInputConnectionForTest();
         return ImeTestUtils.runBlockingOnHandlerNoException(
                 connection.getHandler(), new Callable<CharSequence>() {
@@ -860,14 +861,14 @@
     }
 
     private void setVisibileOnUiThread(final boolean show) {
-        final ContentViewCoreImpl contentViewCore = mContentViewCore;
+        final WebContents webContents = mActivityTestRule.getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 if (show) {
-                    contentViewCore.onShow();
+                    webContents.onShow();
                 } else {
-                    contentViewCore.onHide();
+                    webContents.onHide();
                 }
             }
         });
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
index 172c989..9d3daba 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
@@ -45,7 +45,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                mActivityTestRule.getContentViewCore().onHide();
+                mActivityTestRule.getWebContents().onHide();
             }
         });
     }
@@ -54,7 +54,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                mActivityTestRule.getContentViewCore().onShow();
+                mActivityTestRule.getWebContents().onShow();
             }
         });
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
index 24c9350..87d4bee 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeActivityTestRule.java
@@ -29,9 +29,9 @@
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper.InputConnectionProvider;
+import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.ContentViewCore;
 import org.chromium.content_public.browser.ImeAdapter;
-import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.ui.base.ime.TextInputType;
 
@@ -343,7 +343,7 @@
     // After calling this method, we should call assertClipboardContents() to wait for the clipboard
     // to get updated. See cubug.com/621046
     void copy() {
-        final WebContents webContents = getWebContents();
+        final WebContentsImpl webContents = (WebContentsImpl) getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -353,7 +353,7 @@
     }
 
     void cut() {
-        final WebContents webContents = getWebContents();
+        final WebContentsImpl webContents = (WebContentsImpl) getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -375,7 +375,7 @@
     }
 
     void paste() {
-        final WebContents webContents = getWebContents();
+        final WebContentsImpl webContents = (WebContentsImpl) getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -385,7 +385,7 @@
     }
 
     void selectAll() {
-        final WebContents webContents = getWebContents();
+        final WebContentsImpl webContents = (WebContentsImpl) getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -395,7 +395,7 @@
     }
 
     void collapseSelection() {
-        final WebContents webContents = getWebContents();
+        final WebContentsImpl webContents = (WebContentsImpl) getWebContents();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/content/public/browser/background_fetch_delegate.h b/content/public/browser/background_fetch_delegate.h
index 5415f9b..6830505 100644
--- a/content/public/browser/background_fetch_delegate.h
+++ b/content/public/browser/background_fetch_delegate.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -17,6 +18,10 @@
 class GURL;
 class SkBitmap;
 
+namespace gfx {
+class Size;
+}
+
 namespace net {
 class HttpRequestHeaders;
 struct NetworkTrafficAnnotationTag;
@@ -36,6 +41,8 @@
 // BackgroundFetchDelegateProxy.
 class CONTENT_EXPORT BackgroundFetchDelegate {
  public:
+  using GetIconDisplaySizeCallback = base::OnceCallback<void(const gfx::Size&)>;
+
   // Client interface that a BackgroundFetchDelegate would use to signal the
   // progress of a background fetch.
   class Client {
@@ -75,6 +82,9 @@
 
   virtual ~BackgroundFetchDelegate();
 
+  // Gets size of the icon to display with the Background Fetch UI.
+  virtual void GetIconDisplaySize(GetIconDisplaySizeCallback callback) = 0;
+
   // Creates a new download grouping identified by |job_unique_id|. Further
   // downloads started by DownloadUrl will also use this |job_unique_id| so that
   // a notification can be updated with the current status. If the download was
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index 666ab793..3869201 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -172,9 +172,11 @@
   // thread.  To DCHECK this, use the DCHECK_CURRENTLY_ON() macro above.
   static bool CurrentlyOn(ID identifier) WARN_UNUSED_RESULT;
 
+  // Deprecated: This is equivalent to IsThreadInitialized().
   // Callable on any thread.  Returns whether the threads message loop is valid.
   // If this returns false it means the thread is in the process of shutting
   // down.
+  // TODO(gab): Replace callers with IsThreadInitialized().
   static bool IsMessageLoopValid(ID identifier) WARN_UNUSED_RESULT;
 
   // If the current message loop is one of the known threads, returns true and
@@ -188,16 +190,12 @@
 
   // Sets the delegate for BrowserThread::IO.
   //
-  // This only supports the IO thread as it doesn't work for potentially
-  // redirected threads (ref. http://crbug.com/653916) and also doesn't make
-  // sense for the UI thread.
-  //
   // Only one delegate may be registered at a time. The delegate may be
   // unregistered by providing a nullptr pointer.
   //
-  // If the caller unregisters the delegate before CleanUp has been called, it
-  // must perform its own locking to ensure the delegate is not deleted while
-  // unregistering.
+  // The delegate can only be registered through this call before
+  // BrowserThreadImpl(BrowserThread::IO) is created and unregistered after
+  // it was destroyed and its underlying thread shutdown.
   static void SetIOThreadDelegate(BrowserThreadDelegate* delegate);
 
   // Use these templates in conjunction with RefCountedThreadSafe or scoped_ptr
diff --git a/content/public/browser/browser_thread_delegate.h b/content/public/browser/browser_thread_delegate.h
index 696b76d..3eb823c 100644
--- a/content/public/browser/browser_thread_delegate.h
+++ b/content/public/browser/browser_thread_delegate.h
@@ -5,22 +5,20 @@
 #ifndef CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_DELEGATE_H_
 #define CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_DELEGATE_H_
 
+#include "content/common/content_export.h"
+
 namespace content {
 
-// BrowserThread::SetDelegate was deprecated, this is now only used by
-// BrowserThread::SetIOThreadDelegate.
-//
-// When registered as such, it will schedule to run Init() before the message
-// loop begins and receive a CleanUp call right after the message loop ends (and
-// before the BrowserThread has done its own clean-up).
+// A Delegate for content embedders to perform extra initialization/cleanup on
+// BrowserThread::IO.
 class BrowserThreadDelegate {
  public:
   virtual ~BrowserThreadDelegate() = default;
 
-  // Called prior to starting the message loop
+  // Called prior to completing initialization of BrowserThread::IO.
   virtual void Init() = 0;
 
-  // Called just after the message loop ends.
+  // Called during teardown of BrowserThread::IO.
   virtual void CleanUp() = 0;
 };
 
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 65322f3..88371aa10 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -214,7 +214,7 @@
   IPC_STRUCT_TRAITS_MEMBER(clobber_user_agent_initial_scale_quirk)
   IPC_STRUCT_TRAITS_MEMBER(ignore_main_frame_overflow_hidden_quirk)
   IPC_STRUCT_TRAITS_MEMBER(report_screen_size_in_physical_pixels_quirk)
-  IPC_STRUCT_TRAITS_MEMBER(resue_global_for_unowned_main_frame)
+  IPC_STRUCT_TRAITS_MEMBER(reuse_global_for_unowned_main_frame)
   IPC_STRUCT_TRAITS_MEMBER(spellcheck_enabled_by_default)
   IPC_STRUCT_TRAITS_MEMBER(video_fullscreen_orientation_lock_enabled)
   IPC_STRUCT_TRAITS_MEMBER(video_rotate_to_fullscreen_enabled)
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 6ad786b8..c6debfc 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -115,7 +115,7 @@
 // same-origin to the top frame, or if a user gesture is being processed.
 const base::Feature kFramebustingNeedsSameOriginOrUserGesture{
     "FramebustingNeedsSameOriginOrUserGesture",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables extended Gamepad API features like motion tracking and haptics.
 const base::Feature kGamepadExtensions{"GamepadExtensions",
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index c65520b..498a0a97 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -574,7 +574,12 @@
 const char kMainFrameResizesAreOrientationChanges[] =
     "main-frame-resizes-are-orientation-changes";
 
-// Specifies the maximum disk cache size for the ApplicationCache. Default
+// Specifies the maximum cache size per an origin for the ApplicationCache.
+// The default value is 5MB.
+const char kMaxAppCacheOriginCacheSizeMb[] =
+    "max-appcache-origin-cache-size-mb";
+
+// Specifies the maximum disk cache size for the ApplicationCache. The default
 // value is 250MB.
 const char kMaxAppCacheDiskCacheSizeMb[] = "max-appcache-disk-cache-size-mb";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 654abd3..00376e4 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -171,6 +171,7 @@
 CONTENT_EXPORT extern const char kLoggingLevel[];
 CONTENT_EXPORT extern const char kLogFile[];
 CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
+extern const char kMaxAppCacheOriginCacheSizeMb[];
 extern const char kMaxAppCacheDiskCacheSizeMb[];
 extern const char kMaxUntiledLayerHeight[];
 extern const char kMaxUntiledLayerWidth[];
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 9e2e613..23d47c5 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -30,7 +30,12 @@
                    WebSettings::kV8CacheOptionsDefault);
 STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_NONE, WebSettings::kV8CacheOptionsNone);
 STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_CODE, WebSettings::kV8CacheOptionsCode);
-STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_LAST, WebSettings::kV8CacheOptionsCode);
+STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_CODE_WITHOUT_HEAT_CHECK,
+                   WebSettings::kV8CacheOptionsCodeWithoutHeatCheck);
+STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_FULLCODE_WITHOUT_HEAT_CHECK,
+                   WebSettings::kV8CacheOptionsFullCodeWithoutHeatCheck);
+STATIC_ASSERT_ENUM(V8_CACHE_OPTIONS_LAST,
+                   WebSettings::kV8CacheOptionsFullCodeWithoutHeatCheck);
 
 STATIC_ASSERT_ENUM(SavePreviousDocumentResources::NEVER,
                    WebSettings::SavePreviousDocumentResources::kNever);
@@ -195,7 +200,7 @@
       clobber_user_agent_initial_scale_quirk(false),
       ignore_main_frame_overflow_hidden_quirk(false),
       report_screen_size_in_physical_pixels_quirk(false),
-      resue_global_for_unowned_main_frame(false),
+      reuse_global_for_unowned_main_frame(false),
       spellcheck_enabled_by_default(true),
       video_fullscreen_orientation_lock_enabled(false),
       video_rotate_to_fullscreen_enabled(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 4b79449..50dcb78 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -40,7 +40,9 @@
   V8_CACHE_OPTIONS_DEFAULT,
   V8_CACHE_OPTIONS_NONE,
   V8_CACHE_OPTIONS_CODE,
-  V8_CACHE_OPTIONS_LAST = V8_CACHE_OPTIONS_CODE
+  V8_CACHE_OPTIONS_CODE_WITHOUT_HEAT_CHECK,
+  V8_CACHE_OPTIONS_FULLCODE_WITHOUT_HEAT_CHECK,
+  V8_CACHE_OPTIONS_LAST = V8_CACHE_OPTIONS_FULLCODE_WITHOUT_HEAT_CHECK
 };
 
 // ImageAnimationPolicy is used for controlling image animation
@@ -236,7 +238,7 @@
   bool report_screen_size_in_physical_pixels_quirk;
   // Used by Android_WebView only to support legacy apps that inject script into
   // a top-level initial empty document and expect it to persist on navigation.
-  bool resue_global_for_unowned_main_frame;
+  bool reuse_global_for_unowned_main_frame;
   // Specifies default setting for spellcheck when the spellcheck attribute is
   // not explicitly specified.
   bool spellcheck_enabled_by_default;
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
index 40f93c9..3075ef5 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
@@ -92,27 +92,6 @@
     public void stop() {}
 
     @Override
-    public void cut() {}
-
-    @Override
-    public void copy() {}
-
-    @Override
-    public void paste() {}
-
-    @Override
-    public void pasteAsPlainText() {}
-
-    @Override
-    public void replace(String word) {}
-
-    @Override
-    public void selectAll() {}
-
-    @Override
-    public void collapseSelection() {}
-
-    @Override
     public void onHide() {}
 
     @Override
@@ -122,12 +101,6 @@
     public void setImportance(int importance) {}
 
     @Override
-    public void dismissTextHandles() {}
-
-    @Override
-    public void showContextMenuAtTouchHandle(int x, int y) {}
-
-    @Override
     public void suspendAllMediaPlayers() {}
 
     @Override
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
index dc751dd6..bd157f8 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
@@ -50,12 +50,6 @@
     }
 
     @Override
-    public void onShow() {}
-
-    @Override
-    public void onHide() {}
-
-    @Override
     public void onAttachedToWindow() {}
 
     @Override
diff --git a/content/public/test/browsing_data_remover_test_util.cc b/content/public/test/browsing_data_remover_test_util.cc
index bca0848..184d8063 100644
--- a/content/public/test/browsing_data_remover_test_util.cc
+++ b/content/public/test/browsing_data_remover_test_util.cc
@@ -3,13 +3,15 @@
 // found in the LICENSE file.
 
 #include "content/public/test/browsing_data_remover_test_util.h"
+
+#include "base/bind.h"
 #include "base/task_scheduler/task_scheduler.h"
 
 namespace content {
 
 BrowsingDataRemoverCompletionObserver::BrowsingDataRemoverCompletionObserver(
     BrowsingDataRemover* remover)
-    : message_loop_runner_(new MessageLoopRunner()), observer_(this) {
+    : observer_(this) {
   observer_.Add(remover);
 }
 
@@ -18,17 +20,17 @@
 
 void BrowsingDataRemoverCompletionObserver::BlockUntilCompletion() {
   base::TaskScheduler::GetInstance()->FlushForTesting();
-  message_loop_runner_->Run();
+  run_loop_.Run();
 }
 
 void BrowsingDataRemoverCompletionObserver::OnBrowsingDataRemoverDone() {
   observer_.RemoveAll();
-  message_loop_runner_->Quit();
+  run_loop_.QuitWhenIdle();
 }
 
 BrowsingDataRemoverCompletionInhibitor::BrowsingDataRemoverCompletionInhibitor(
     BrowsingDataRemover* remover)
-    : remover_(remover), message_loop_runner_(new content::MessageLoopRunner) {
+    : remover_(remover), run_loop_(new base::RunLoop) {
   DCHECK(remover);
   remover_->SetWouldCompleteCallbackForTesting(
       base::Bind(&BrowsingDataRemoverCompletionInhibitor::
@@ -51,8 +53,8 @@
 
 void BrowsingDataRemoverCompletionInhibitor::BlockUntilNearCompletion() {
   base::TaskScheduler::GetInstance()->FlushForTesting();
-  message_loop_runner_->Run();
-  message_loop_runner_ = new MessageLoopRunner();
+  run_loop_->Run();
+  run_loop_ = std::make_unique<base::RunLoop>();
 }
 
 void BrowsingDataRemoverCompletionInhibitor::ContinueToCompletion() {
@@ -65,7 +67,7 @@
     const base::Closure& continue_to_completion) {
   DCHECK(continue_to_completion_callback_.is_null());
   continue_to_completion_callback_ = continue_to_completion;
-  message_loop_runner_->Quit();
+  run_loop_->QuitWhenIdle();
 }
 
 }  // namespace content
diff --git a/content/public/test/browsing_data_remover_test_util.h b/content/public/test/browsing_data_remover_test_util.h
index ac069b6..403745c 100644
--- a/content/public/test/browsing_data_remover_test_util.h
+++ b/content/public/test/browsing_data_remover_test_util.h
@@ -5,11 +5,12 @@
 #ifndef CONTENT_PUBLIC_TEST_BROWSING_DATA_REMOVER_TEST_UTIL_H_
 #define CONTENT_PUBLIC_TEST_BROWSING_DATA_REMOVER_TEST_UTIL_H_
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "content/public/browser/browsing_data_remover.h"
-#include "content/public/test/test_utils.h"
 
 namespace content {
 
@@ -28,7 +29,7 @@
   void OnBrowsingDataRemoverDone() override;
 
  private:
-  scoped_refptr<MessageLoopRunner> message_loop_runner_;
+  base::RunLoop run_loop_;
   ScopedObserver<BrowsingDataRemover, BrowsingDataRemover::Observer> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionObserver);
@@ -60,7 +61,7 @@
   // this class is responsible for calling Reset().
   BrowsingDataRemover* remover_;
 
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  std::unique_ptr<base::RunLoop> run_loop_;
   base::Closure continue_to_completion_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionInhibitor);
diff --git a/content/public/test/test_browser_thread.cc b/content/public/test/test_browser_thread.cc
index d2a4bcd..63876d0a 100644
--- a/content/public/test/test_browser_thread.cc
+++ b/content/public/test/test_browser_thread.cc
@@ -9,71 +9,32 @@
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
+#include "content/browser/browser_process_sub_thread.h"
 #include "content/browser/browser_thread_impl.h"
-#include "content/browser/notification_service_impl.h"
-
-#if defined(OS_WIN)
-#include "base/win/scoped_com_initializer.h"
-#endif
 
 namespace content {
 
-class TestBrowserThreadImpl : public BrowserThreadImpl {
- public:
-  explicit TestBrowserThreadImpl(BrowserThread::ID identifier)
-      : BrowserThreadImpl(identifier) {}
-
-  TestBrowserThreadImpl(BrowserThread::ID identifier,
-                        base::MessageLoop* message_loop)
-      : BrowserThreadImpl(identifier, message_loop) {}
-
-  ~TestBrowserThreadImpl() override { Stop(); }
-
-  void Init() override {
-#if defined(OS_WIN)
-    com_initializer_ = std::make_unique<base::win::ScopedCOMInitializer>();
-#endif
-
-    notification_service_ = std::make_unique<NotificationServiceImpl>();
-    BrowserThreadImpl::Init();
-  }
-
-  void CleanUp() override {
-    BrowserThreadImpl::CleanUp();
-    notification_service_.reset();
-#if defined(OS_WIN)
-    com_initializer_.reset();
-#endif
-  }
-
- private:
-#if defined(OS_WIN)
-  std::unique_ptr<base::win::ScopedCOMInitializer> com_initializer_;
-#endif
-
-  std::unique_ptr<NotificationService> notification_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestBrowserThreadImpl);
-};
-
 TestBrowserThread::TestBrowserThread(BrowserThread::ID identifier)
-    : impl_(new TestBrowserThreadImpl(identifier)), identifier_(identifier) {}
+    : identifier_(identifier),
+      real_thread_(std::make_unique<BrowserProcessSubThread>(identifier_)) {
+  real_thread_->AllowBlockingForTesting();
+}
 
 TestBrowserThread::TestBrowserThread(BrowserThread::ID identifier,
                                      base::MessageLoop* message_loop)
-    : impl_(new TestBrowserThreadImpl(identifier, message_loop)),
-      identifier_(identifier) {}
+    : identifier_(identifier),
+      fake_thread_(
+          new BrowserThreadImpl(identifier_, message_loop->task_runner())) {}
 
 TestBrowserThread::~TestBrowserThread() {
   // The upcoming BrowserThreadImpl::ResetGlobalsForTesting() call requires that
-  // |impl_| have triggered the shutdown phase for its BrowserThread::ID. This
-  // either happens when the thread is stopped (if real) or destroyed (when fake
-  // -- i.e. using an externally provided MessageLoop).
-  impl_.reset();
+  // |identifier_| have completed its SHUTDOWN phase.
+  real_thread_.reset();
+  fake_thread_.reset();
 
-  // Resets BrowserThreadImpl's globals so that |impl_| is no longer bound to
-  // |identifier_|. This is fine since the underlying MessageLoop has already
-  // been flushed and deleted in Stop(). In the case of an externally provided
+  // Resets BrowserThreadImpl's globals so that |identifier_| is no longer
+  // bound. This is fine since the underlying MessageLoop has already been
+  // flushed and deleted above. In the case of an externally provided
   // MessageLoop however, this means that TaskRunners obtained through
   // |BrowserThreadImpl::GetTaskRunnerForThread(identifier_)| will no longer
   // recognize their BrowserThreadImpl for RunsTasksInCurrentSequence(). This
@@ -87,30 +48,34 @@
   BrowserThreadImpl::ResetGlobalsForTesting(identifier_);
 }
 
-bool TestBrowserThread::Start() {
-  return impl_->Start();
+void TestBrowserThread::Start() {
+  CHECK(real_thread_->Start());
+  RegisterAsBrowserThread();
 }
 
-bool TestBrowserThread::StartAndWaitForTesting() {
-  return impl_->StartAndWaitForTesting();
+void TestBrowserThread::StartAndWaitForTesting() {
+  CHECK(real_thread_->StartAndWaitForTesting());
+  RegisterAsBrowserThread();
 }
 
-bool TestBrowserThread::StartIOThread() {
+void TestBrowserThread::StartIOThread() {
+  StartIOThreadUnregistered();
+  RegisterAsBrowserThread();
+}
+
+void TestBrowserThread::StartIOThreadUnregistered() {
   base::Thread::Options options;
   options.message_loop_type = base::MessageLoop::TYPE_IO;
-  return impl_->StartWithOptions(options);
+  CHECK(real_thread_->StartWithOptions(options));
 }
 
-void TestBrowserThread::InitIOThreadDelegate() {
-  impl_->InitIOThreadDelegate();
+void TestBrowserThread::RegisterAsBrowserThread() {
+  real_thread_->RegisterAsBrowserThread();
 }
 
 void TestBrowserThread::Stop() {
-  impl_->Stop();
-}
-
-bool TestBrowserThread::IsRunning() {
-  return impl_->IsRunning();
+  if (real_thread_)
+    real_thread_->Stop();
 }
 
 }  // namespace content
diff --git a/content/public/test/test_browser_thread.h b/content/public/test/test_browser_thread.h
index ceb39ca..161142c 100644
--- a/content/public/test/test_browser_thread.h
+++ b/content/public/test/test_browser_thread.h
@@ -12,20 +12,27 @@
 
 namespace base {
 class MessageLoop;
+class Thread;
 }
 
 namespace content {
 
-class TestBrowserThreadImpl;
+class BrowserProcessSubThread;
+class BrowserThreadImpl;
 
 // DEPRECATED: use TestBrowserThreadBundle instead. See http://crbug.com/272091
 // A BrowserThread for unit tests; this lets unit tests in chrome/ create
 // BrowserThread instances.
 class TestBrowserThread {
  public:
+  // Constructs a TestBrowserThread with a |real_thread_| and starts it (with a
+  // MessageLoopForIO if |identifier == BrowserThread::IO|.
   explicit TestBrowserThread(BrowserThread::ID identifier);
+
+  // Constructs a TestBrowserThread based on |message_loop| (no |real_thread_|).
   TestBrowserThread(BrowserThread::ID identifier,
                     base::MessageLoop* message_loop);
+
   ~TestBrowserThread();
 
   // We provide a subset of the capabilities of the Thread interface
@@ -34,29 +41,35 @@
   // interface.
 
   // Starts the thread with a generic message loop.
-  bool Start();
+  void Start();
 
   // Starts the thread with a generic message loop and waits for the
   // thread to run.
-  bool StartAndWaitForTesting();
+  void StartAndWaitForTesting();
 
   // Starts the thread with an IOThread message loop.
-  bool StartIOThread();
+  void StartIOThread();
 
-  // Initializes the BrowserThreadDelegate.
-  void InitIOThreadDelegate();
+  // Together these are the same as StartIOThread(). They can be called in
+  // phases to test binding BrowserThread::IO after its underlying thread was
+  // started.
+  void StartIOThreadUnregistered();
+  void RegisterAsBrowserThread();
 
-  // Stops the thread.
+  // Stops the thread, no-op if this is not a real thread.
   void Stop();
 
-  // Returns true if the thread is running.
-  bool IsRunning();
-
  private:
-  std::unique_ptr<TestBrowserThreadImpl> impl_;
-
   const BrowserThread::ID identifier_;
 
+  // A real thread which represents |identifier_| when constructor #1 is used
+  // (null otherwise).
+  std::unique_ptr<BrowserProcessSubThread> real_thread_;
+
+  // Binds |identifier_| to |message_loop| when constructor #2 is used (null
+  // otherwise).
+  std::unique_ptr<BrowserThreadImpl> fake_thread_;
+
   DISALLOW_COPY_AND_ASSIGN(TestBrowserThread);
 };
 
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc
index 6d630d3..ab6766cb 100644
--- a/content/public/test/url_loader_interceptor.cc
+++ b/content/public/test/url_loader_interceptor.cc
@@ -264,7 +264,7 @@
   network::ResourceResponseHead response;
   response.headers = info.headers;
   response.headers->GetMimeType(&response.mime_type);
-  client->OnReceiveResponse(response, base::nullopt, nullptr);
+  client->OnReceiveResponse(response, nullptr);
 
   uint32_t bytes_written = body.size();
   mojo::DataPipe data_pipe;
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index de811484..36a92be 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -176,7 +176,6 @@
   // network::mojom::URLLoaderClient overrides:
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     DCHECK_EQ(Status::kStarted, status_);
     // Existing callers need URL and HTTP status code. URL is already set in
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.cc b/content/renderer/loader/child_url_loader_factory_bundle.cc
index a575899..feb92de 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/child_url_loader_factory_bundle.cc
@@ -44,9 +44,8 @@
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(
       const network::ResourceResponseHead& head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
-    client_sink_->OnReceiveResponse(head, ssl_info, std::move(downloaded_file));
+    client_sink_->OnReceiveResponse(head, std::move(downloaded_file));
   }
 
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
@@ -166,8 +165,7 @@
         std::move(override_iter->second);
     subresource_overrides_.erase(override_iter);
 
-    client->OnReceiveResponse(transferrable_loader->head, base::nullopt,
-                              nullptr);
+    client->OnReceiveResponse(transferrable_loader->head, nullptr);
     mojo::MakeStrongBinding(
         std::make_unique<URLLoaderRelay>(
             network::mojom::URLLoaderPtr(
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 5d42418..34ad0e4 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -574,7 +574,7 @@
   // the request. ResourceResponseHead can be empty here because we
   // pull the StreamOverride's one in
   // WebURLLoaderImpl::Context::OnReceivedResponse.
-  client_ptr->OnReceiveResponse(network::ResourceResponseHead(), base::nullopt,
+  client_ptr->OnReceiveResponse(network::ResourceResponseHead(),
                                 network::mojom::DownloadedTempFilePtr());
   // TODO(clamy): Move the replaying of redirects from WebURLLoaderImpl here.
 
diff --git a/content/renderer/loader/resource_dispatcher_unittest.cc b/content/renderer/loader/resource_dispatcher_unittest.cc
index c3da60c9..828ff1e2 100644
--- a/content/renderer/loader/resource_dispatcher_unittest.cc
+++ b/content/renderer/loader/resource_dispatcher_unittest.cc
@@ -85,7 +85,7 @@
     head.headers = new net::HttpResponseHeaders(raw_headers);
     head.mime_type = kTestPageMimeType;
     head.charset = kTestPageCharset;
-    client->OnReceiveResponse(head, {}, {});
+    client->OnReceiveResponse(head, {});
   }
 
   std::unique_ptr<network::ResourceRequest> CreateResourceRequest() {
@@ -322,7 +322,7 @@
     ASSERT_EQ(1u, loader_and_clients_.size());
     auto client = std::move(loader_and_clients_[0].second);
     loader_and_clients_.clear();
-    client->OnReceiveResponse(response_head, {}, {});
+    client->OnReceiveResponse(response_head, {});
   }
 
   const network::ResourceResponseInfo& response_info() const {
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index 4d7badc..0e7c4b23 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -233,7 +233,6 @@
 
 void URLLoaderClientImpl::OnReceiveResponse(
     const network::ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   has_received_response_ = true;
   downloaded_file_ = std::move(downloaded_file);
diff --git a/content/renderer/loader/url_loader_client_impl.h b/content/renderer/loader/url_loader_client_impl.h
index 375aa92..26b9241 100644
--- a/content/renderer/loader/url_loader_client_impl.h
+++ b/content/renderer/loader/url_loader_client_impl.h
@@ -62,7 +62,6 @@
   // network::mojom::URLLoaderClient implementation
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index eca5f99..eb76805b 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -79,7 +79,7 @@
 TEST_F(URLLoaderClientImplTest, OnReceiveResponse) {
   network::ResourceResponseHead response_head;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
 
   EXPECT_FALSE(request_peer_context_.received_response);
   base::RunLoop().RunUntilIdle();
@@ -89,7 +89,7 @@
 TEST_F(URLLoaderClientImplTest, ResponseBody) {
   network::ResourceResponseHead response_head;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
 
   EXPECT_FALSE(request_peer_context_.received_response);
   base::RunLoop().RunUntilIdle();
@@ -122,7 +122,7 @@
 TEST_F(URLLoaderClientImplTest, OnDataDownloaded) {
   network::ResourceResponseHead response_head;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnDataDownloaded(8, 13);
   url_loader_client_->OnDataDownloaded(2, 1);
 
@@ -140,7 +140,7 @@
   std::vector<uint8_t> metadata;
   metadata.push_back('a');
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnReceiveCachedMetadata(metadata);
 
   EXPECT_FALSE(request_peer_context_.received_response);
@@ -154,7 +154,7 @@
 TEST_F(URLLoaderClientImplTest, OnTransferSizeUpdated) {
   network::ResourceResponseHead response_head;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnTransferSizeUpdated(4);
   url_loader_client_->OnTransferSizeUpdated(4);
 
@@ -169,7 +169,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnComplete(status);
 
   EXPECT_FALSE(request_peer_context_.received_response);
@@ -183,7 +183,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   url_loader_client_->OnStartLoadingResponseBody(
       std::move(data_pipe.consumer_handle));
@@ -217,7 +217,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   url_loader_client_->OnStartLoadingResponseBody(
       std::move(data_pipe.consumer_handle));
@@ -249,7 +249,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   url_loader_client_->OnStartLoadingResponseBody(
       std::move(data_pipe.consumer_handle));
@@ -278,7 +278,7 @@
   ASSERT_EQ(MOJO_RESULT_OK, result);
   EXPECT_EQ(5u, size);
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnStartLoadingResponseBody(
       std::move(data_pipe.consumer_handle));
   url_loader_client_->OnComplete(status);
@@ -299,7 +299,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnComplete(status);
 
   EXPECT_FALSE(request_peer_context_.received_response);
@@ -324,7 +324,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   uint32_t size = 5;
   MojoResult result = data_pipe.producer_handle->WriteData(
@@ -365,7 +365,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   uint32_t size = 5;
   MojoResult result = data_pipe.producer_handle->WriteData(
@@ -413,7 +413,7 @@
   network::URLLoaderCompletionStatus status;
 
   url_loader_client_->OnReceiveRedirect(redirect_info, response_head);
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   mojo::DataPipe data_pipe(DataPipeOptions());
   uint32_t size = 5;
   MojoResult result = data_pipe.producer_handle->WriteData(
@@ -474,7 +474,7 @@
   network::ResourceResponseHead response_head;
   network::URLLoaderCompletionStatus status;
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
 
   url_loader_client_->OnTransferSizeUpdated(4);
   url_loader_client_->OnComplete(status);
@@ -523,7 +523,7 @@
   ASSERT_EQ(MOJO_RESULT_OK, result);
   EXPECT_EQ(5u, size);
 
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head, nullptr);
   url_loader_client_->OnStartLoadingResponseBody(
       std::move(data_pipe.consumer_handle));
   url_loader_client_->OnComplete(status);
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index af41e0a..f5e4c54 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -47,10 +47,12 @@
 #include "net/cert/cert_status_flags.h"
 #include "net/cert/ct_sct_to_string.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_info.h"
 #include "net/url_request/url_request_data_job.h"
 #include "services/network/loader_util.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -245,6 +247,12 @@
           sct_and_status.sct->signature.signature_data.length())));
 }
 
+WebString CryptoBufferAsWebString(const CRYPTO_BUFFER* buffer) {
+  base::StringPiece sp = net::x509_util::CryptoBufferAsStringPiece(buffer);
+  return blink::WebString::FromLatin1(
+      reinterpret_cast<const blink::WebLChar*>(sp.begin()), sp.size());
+}
+
 void SetSecurityStyleAndDetails(const GURL& url,
                                 const network::ResourceResponseInfo& info,
                                 WebURLResponse* response,
@@ -261,42 +269,47 @@
   // The resource loader does not provide a guarantee that requests always have
   // security info (such as a certificate) attached. Use WebSecurityStyleUnknown
   // in this case where there isn't enough information to be useful.
-  if (info.certificate.empty()) {
+  if (!info.ssl_info.has_value()) {
     response->SetSecurityStyle(blink::kWebSecurityStyleUnknown);
     return;
   }
 
-  int ssl_version =
-      net::SSLConnectionStatusToVersion(info.ssl_connection_status);
-  const char* protocol;
-  net::SSLVersionToString(&protocol, ssl_version);
+  const net::SSLInfo& ssl_info = *info.ssl_info;
 
-  const char* key_exchange;
-  const char* cipher;
-  const char* mac;
-  bool is_aead;
-  bool is_tls13;
-  uint16_t cipher_suite =
-      net::SSLConnectionStatusToCipherSuite(info.ssl_connection_status);
-  net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
-                               &is_tls13, cipher_suite);
-  if (key_exchange == nullptr) {
-    DCHECK(is_tls13);
-    key_exchange = "";
-  }
-
-  if (mac == nullptr) {
-    DCHECK(is_aead);
-    mac = "";
-  }
-
+  const char* protocol = "";
+  const char* key_exchange = "";
+  const char* cipher = "";
+  const char* mac = "";
   const char* key_exchange_group = "";
-  if (info.ssl_key_exchange_group != 0) {
-    // Historically the field was named 'curve' rather than 'group'.
-    key_exchange_group = SSL_get_curve_name(info.ssl_key_exchange_group);
-    if (!key_exchange_group) {
-      NOTREACHED();
-      key_exchange_group = "";
+
+  if (ssl_info.connection_status) {
+    int ssl_version =
+        net::SSLConnectionStatusToVersion(ssl_info.connection_status);
+    net::SSLVersionToString(&protocol, ssl_version);
+
+    bool is_aead;
+    bool is_tls13;
+    uint16_t cipher_suite =
+        net::SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
+    net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
+                                 &is_tls13, cipher_suite);
+    if (key_exchange == nullptr) {
+      DCHECK(is_tls13);
+      key_exchange = "";
+    }
+
+    if (mac == nullptr) {
+      DCHECK(is_aead);
+      mac = "";
+    }
+
+    if (ssl_info.key_exchange_group != 0) {
+      // Historically the field was named 'curve' rather than 'group'.
+      key_exchange_group = SSL_get_curve_name(ssl_info.key_exchange_group);
+      if (!key_exchange_group) {
+        NOTREACHED();
+        key_exchange_group = "";
+      }
     }
   }
 
@@ -304,15 +317,12 @@
       GetSecurityStyleForResource(url, info.cert_status));
 
   blink::WebURLResponse::SignedCertificateTimestampList sct_list(
-      info.signed_certificate_timestamps.size());
+      ssl_info.signed_certificate_timestamps.size());
 
   for (size_t i = 0; i < sct_list.size(); ++i)
-    sct_list[i] = NetSCTToBlinkSCT(info.signed_certificate_timestamps[i]);
+    sct_list[i] = NetSCTToBlinkSCT(ssl_info.signed_certificate_timestamps[i]);
 
-  scoped_refptr<net::X509Certificate> cert(
-      net::X509Certificate::CreateFromBytes(info.certificate[0].data(),
-                                            info.certificate[0].size()));
-  if (!cert) {
+  if (!ssl_info.cert) {
     NOTREACHED();
     response->SetSecurityStyle(blink::kWebSecurityStyleUnknown);
     return;
@@ -320,7 +330,7 @@
 
   std::vector<std::string> san_dns;
   std::vector<std::string> san_ip;
-  cert->GetSubjectAltName(&san_dns, &san_ip);
+  ssl_info.cert->GetSubjectAltName(&san_dns, &san_ip);
   blink::WebVector<blink::WebString> web_san(san_dns.size() + san_ip.size());
   std::transform(
       san_dns.begin(), san_dns.end(), web_san.begin(),
@@ -332,19 +342,20 @@
                    return blink::WebString::FromLatin1(ip.ToString());
                  });
 
-  blink::WebVector<blink::WebString> web_cert(info.certificate.size());
-  std::transform(
-      info.certificate.begin(), info.certificate.end(), web_cert.begin(),
-      [](const std::string& h) { return blink::WebString::FromLatin1(h); });
+  blink::WebVector<blink::WebString> web_cert;
+  web_cert.reserve(ssl_info.cert->intermediate_buffers().size() + 1);
+  web_cert.emplace_back(CryptoBufferAsWebString(ssl_info.cert->cert_buffer()));
+  for (const auto& cert : ssl_info.cert->intermediate_buffers())
+    web_cert.emplace_back(CryptoBufferAsWebString(cert.get()));
 
   blink::WebURLResponse::WebSecurityDetails webSecurityDetails(
       WebString::FromASCII(protocol), WebString::FromASCII(key_exchange),
       WebString::FromASCII(key_exchange_group), WebString::FromASCII(cipher),
       WebString::FromASCII(mac),
-      WebString::FromUTF8(cert->subject().common_name), web_san,
-      WebString::FromUTF8(cert->issuer().common_name),
-      cert->valid_start().ToDoubleT(), cert->valid_expiry().ToDoubleT(),
-      web_cert, sct_list);
+      WebString::FromUTF8(ssl_info.cert->subject().common_name), web_san,
+      WebString::FromUTF8(ssl_info.cert->issuer().common_name),
+      ssl_info.cert->valid_start().ToDoubleT(),
+      ssl_info.cert->valid_expiry().ToDoubleT(), web_cert, sct_list);
 
   response->SetSecurityDetails(webSecurityDetails);
 }
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index aa92d4c..aac23cc 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -699,11 +699,14 @@
   base::StringPiece cert1_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
 
-  network::ResourceResponseInfo info;
+  net::SSLInfo ssl_info;
+  ssl_info.cert =
+      net::X509Certificate::CreateFromDERCertChain({cert0_der, cert1_der});
   net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
-                                     &info.ssl_connection_status);
-  info.certificate.emplace_back(cert0_der);
-  info.certificate.emplace_back(cert1_der);
+                                     &ssl_info.connection_status);
+
+  network::ResourceResponseInfo info;
+  info.ssl_info = ssl_info;
   blink::WebURLResponse web_url_response;
   WebURLLoaderImpl::PopulateURLResponse(url, info, &web_url_response, true);
 
@@ -735,10 +738,12 @@
   base::StringPiece cert0_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
 
-  network::ResourceResponseInfo info;
+  net::SSLInfo ssl_info;
   net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
-                                     &info.ssl_connection_status);
-  info.certificate.emplace_back(cert0_der);
+                                     &ssl_info.connection_status);
+  ssl_info.cert = certs[0];
+  network::ResourceResponseInfo info;
+  info.ssl_info = ssl_info;
   blink::WebURLResponse web_url_response;
   WebURLLoaderImpl::PopulateURLResponse(url, info, &web_url_response, true);
 
diff --git a/content/renderer/media/stream/user_media_client_impl_unittest.cc b/content/renderer/media/stream/user_media_client_impl_unittest.cc
index a066321f..0146761 100644
--- a/content/renderer/media/stream/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/stream/user_media_client_impl_unittest.cc
@@ -328,8 +328,7 @@
 
   MediaStreamAudioSource* CreateAudioSource(
       const MediaStreamDevice& device,
-      const MediaStreamSource::ConstraintsCallback& source_ready,
-      bool* has_sw_echo_cancellation) override {
+      const MediaStreamSource::ConstraintsCallback& source_ready) override {
     MediaStreamAudioSource* source;
     if (create_source_that_fails_) {
       class FailedAtLifeAudioSource : public MediaStreamAudioSource {
@@ -355,7 +354,6 @@
                          source_ready, source));
     }
 
-    *has_sw_echo_cancellation = false;
     return source;
   }
 
diff --git a/content/renderer/media/stream/user_media_processor.cc b/content/renderer/media/stream/user_media_processor.cc
index 603e1b49..7735ae6 100644
--- a/content/renderer/media/stream/user_media_processor.cc
+++ b/content/renderer/media/stream/user_media_processor.cc
@@ -96,14 +96,27 @@
          source == kMediaStreamSourceScreen;
 }
 
-void SurfaceHardwareEchoCancellationSetting(
-    blink::WebMediaStreamSource* source) {
+void SurfaceAudioProcessingSettings(blink::WebMediaStreamSource* source) {
   MediaStreamAudioSource* source_impl =
       static_cast<MediaStreamAudioSource*>(source->GetExtraData());
   media::AudioParameters params = source_impl->GetAudioParameters();
-  if (params.IsValid() &&
-      (params.effects() & media::AudioParameters::ECHO_CANCELLER))
-    source->SetEchoCancellation(true);
+  bool hw_echo_cancellation =
+      params.IsValid() &&
+      (params.effects() & media::AudioParameters::ECHO_CANCELLER);
+
+  bool sw_echo_cancellation = false, auto_gain_control = false,
+       noise_supression = false;
+  if (ProcessedLocalAudioSource* processed_source =
+          ProcessedLocalAudioSource::From(source_impl)) {
+    AudioProcessingProperties properties =
+        processed_source->audio_processing_properties();
+    sw_echo_cancellation = properties.enable_sw_echo_cancellation;
+    auto_gain_control = properties.goog_auto_gain_control;
+    noise_supression = properties.goog_noise_suppression;
+  }
+  source->SetAudioProcessingProperties(
+      hw_echo_cancellation || sw_echo_cancellation, auto_gain_control,
+      noise_supression);
 }
 
 }  // namespace
@@ -816,9 +829,8 @@
       &UserMediaProcessor::OnAudioSourceStartedOnAudioThread,
       base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr());
 
-  bool has_sw_echo_cancellation = false;
-  MediaStreamAudioSource* const audio_source = CreateAudioSource(
-      device, std::move(source_ready), &has_sw_echo_cancellation);
+  MediaStreamAudioSource* const audio_source =
+      CreateAudioSource(device, std::move(source_ready));
   audio_source->SetStopCallback(base::Bind(
       &UserMediaProcessor::OnLocalSourceStopped, weak_factory_.GetWeakPtr()));
 
@@ -830,19 +842,12 @@
 
   source.SetExtraData(audio_source);  // Takes ownership.
   source.SetCapabilities(capabilities);
-  // At this point it is known if software echo cancellation will be used, but
-  // final audio parameters for the source are not set yet, so it is not yet
-  // known if hardware echo cancellation will actually be used. That information
-  // is known and surfaced in CreateAudioTracks(), after the track is connected
-  // to the source.
-  source.SetEchoCancellation(has_sw_echo_cancellation);
   return source;
 }
 
 MediaStreamAudioSource* UserMediaProcessor::CreateAudioSource(
     const MediaStreamDevice& device,
-    const MediaStreamSource::ConstraintsCallback& source_ready,
-    bool* has_sw_echo_cancellation) {
+    const MediaStreamSource::ConstraintsCallback& source_ready) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
 
@@ -856,7 +861,6 @@
   if (IsScreenCaptureMediaType(device.type) ||
       !MediaStreamAudioProcessor::WouldModifyAudio(
           audio_processing_properties)) {
-    *has_sw_echo_cancellation = false;
     return new LocalMediaStreamAudioSource(
         render_frame_->GetRoutingID(), device, stream_controls->hotword_enabled,
         stream_controls->disable_local_echo, source_ready);
@@ -864,8 +868,6 @@
 
   // The audio device is not associated with screen capture and also requires
   // processing.
-  *has_sw_echo_cancellation =
-      audio_processing_properties.enable_sw_echo_cancellation;
   return new ProcessedLocalAudioSource(
       render_frame_->GetRoutingID(), device, stream_controls->hotword_enabled,
       stream_controls->disable_local_echo, audio_processing_properties,
@@ -946,9 +948,9 @@
     (*webkit_tracks)[i].Initialize(source);
     current_request_info_->StartAudioTrack((*webkit_tracks)[i], is_pending);
     // At this point the source has started, and its audio parameters have been
-    // set. From the parameters, it is known if hardware echo cancellation is
-    // being used. If this is the case, let |source| know.
-    SurfaceHardwareEchoCancellationSetting(&source);
+    // set. Thus, all audio processing properties are known and can be surfaced
+    // to |source|.
+    SurfaceAudioProcessingSettings(&source);
   }
 }
 
diff --git a/content/renderer/media/stream/user_media_processor.h b/content/renderer/media/stream/user_media_processor.h
index de3eff05..48edc33 100644
--- a/content/renderer/media/stream/user_media_processor.h
+++ b/content/renderer/media/stream/user_media_processor.h
@@ -127,8 +127,7 @@
   // http://crbug.com/764293
   virtual MediaStreamAudioSource* CreateAudioSource(
       const MediaStreamDevice& device,
-      const MediaStreamSource::ConstraintsCallback& source_ready,
-      bool* has_sw_echo_cancellation);
+      const MediaStreamSource::ConstraintsCallback& source_ready);
   virtual MediaStreamVideoSource* CreateVideoSource(
       const MediaStreamDevice& device,
       const MediaStreamSource::SourceStoppedCallback& stop_callback);
diff --git a/content/renderer/media/webrtc/mock_peer_connection_impl.cc b/content/renderer/media/webrtc/mock_peer_connection_impl.cc
index ab80a8a0..21616e4 100644
--- a/content/renderer/media/webrtc/mock_peer_connection_impl.cc
+++ b/content/renderer/media/webrtc/mock_peer_connection_impl.cc
@@ -398,6 +398,18 @@
   callback->OnStatsDelivered(stats_report_);
 }
 
+void MockPeerConnectionImpl::GetStats(
+    rtc::scoped_refptr<webrtc::RtpSenderInterface> selector,
+    rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) {
+  callback->OnStatsDelivered(stats_report_);
+}
+
+void MockPeerConnectionImpl::GetStats(
+    rtc::scoped_refptr<webrtc::RtpReceiverInterface> selector,
+    rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) {
+  callback->OnStatsDelivered(stats_report_);
+}
+
 void MockPeerConnectionImpl::SetGetStatsReport(webrtc::RTCStatsReport* report) {
   stats_report_ = report;
 }
diff --git a/content/renderer/media/webrtc/mock_peer_connection_impl.h b/content/renderer/media/webrtc/mock_peer_connection_impl.h
index f1fc772c..6b8e6f2 100644
--- a/content/renderer/media/webrtc/mock_peer_connection_impl.h
+++ b/content/renderer/media/webrtc/mock_peer_connection_impl.h
@@ -103,6 +103,12 @@
                 webrtc::MediaStreamTrackInterface* track,
                 StatsOutputLevel level) override;
   void GetStats(webrtc::RTCStatsCollectorCallback* callback) override;
+  void GetStats(
+      rtc::scoped_refptr<webrtc::RtpSenderInterface> selector,
+      rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) override;
+  void GetStats(
+      rtc::scoped_refptr<webrtc::RtpReceiverInterface> selector,
+      rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) override;
 
   // Call this function to make sure next call to legacy GetStats fail.
   void SetGetStatsResult(bool result) { getstats_result_ = result; }
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index 13de4ec5..ecb26c4 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -698,52 +698,6 @@
   }
 }
 
-// A stats collector callback.
-// It is invoked on the WebRTC signaling thread and will post a task to invoke
-// |callback| on the thread given in the |main_thread| argument.
-// The argument to the callback will be a |blink::WebRTCStatsReport|.
-class GetRTCStatsCallback : public webrtc::RTCStatsCollectorCallback {
- public:
-  static rtc::scoped_refptr<GetRTCStatsCallback> Create(
-      const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
-      std::unique_ptr<blink::WebRTCStatsReportCallback> callback) {
-    return rtc::scoped_refptr<GetRTCStatsCallback>(
-        new rtc::RefCountedObject<GetRTCStatsCallback>(
-            main_thread, callback.release()));
-  }
-
-  void OnStatsDelivered(
-      const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override {
-    main_thread_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&GetRTCStatsCallback::OnStatsDeliveredOnMainThread, this,
-                       report));
-  }
-
- protected:
-  GetRTCStatsCallback(
-      const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
-      blink::WebRTCStatsReportCallback* callback)
-      : main_thread_(main_thread),
-        callback_(callback) {
-  }
-  ~GetRTCStatsCallback() override { DCHECK(!callback_); }
-
-  void OnStatsDeliveredOnMainThread(
-      const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
-    DCHECK(main_thread_->BelongsToCurrentThread());
-    DCHECK(report);
-    DCHECK(callback_);
-    callback_->OnStatsDelivered(std::unique_ptr<blink::WebRTCStatsReport>(
-        new RTCStatsReport(base::WrapRefCounted(report.get()))));
-    // Make sure the callback is destroyed in the main thread as well.
-    callback_.reset();
-  }
-
-  const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
-  std::unique_ptr<blink::WebRTCStatsReportCallback> callback_;
-};
-
 void GetRTCStatsOnSignalingThread(
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
     scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection,
@@ -751,7 +705,7 @@
   TRACE_EVENT0("webrtc", "GetRTCStatsOnSignalingThread");
 
   native_peer_connection->GetStats(
-      GetRTCStatsCallback::Create(main_thread, std::move(callback)));
+      RTCStatsCollectorCallbackImpl::Create(main_thread, std::move(callback)));
 }
 
 class PeerConnectionUMAObserver : public webrtc::UMAObserver {
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.cc b/content/renderer/media/webrtc/rtc_rtp_sender.cc
index da52674c..28aaa80 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.cc
@@ -206,21 +206,6 @@
     scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
     scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
     rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
-    std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref)
-    : RTCRtpSender(
-          std::move(main_thread),
-          std::move(signaling_thread),
-          std::move(stream_map),
-          std::move(webrtc_sender),
-          std::move(track_ref),
-          std::vector<
-              std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>()) {}
-
-RTCRtpSender::RTCRtpSender(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
-    scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
-    scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
-    rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
     std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
     std::vector<std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>
         stream_refs)
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.h b/content/renderer/media/webrtc/rtc_rtp_sender.h
index 4bd9212..5f79744 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.h
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.h
@@ -33,15 +33,6 @@
                rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
                blink::WebMediaStreamTrack web_track,
                std::vector<blink::WebMediaStream> web_streams);
-  // TODO(hbos): Remove these in favor of the above constructor that creates the
-  // corresponding adapter refs. They won't be needed after
-  // https://crbug.com/738929.
-  RTCRtpSender(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
-      scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
-      scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
-      rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
-      std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref);
   RTCRtpSender(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread,
       scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
diff --git a/content/renderer/media/webrtc/rtc_stats.cc b/content/renderer/media/webrtc/rtc_stats.cc
index 0092c62..0c7478f8 100644
--- a/content/renderer/media/webrtc/rtc_stats.cc
+++ b/content/renderer/media/webrtc/rtc_stats.cc
@@ -7,6 +7,7 @@
 #include <set>
 #include <string>
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "third_party/webrtc/api/stats/rtcstats_objects.h"
@@ -280,6 +281,45 @@
   return web_sequence;
 }
 
+// static
+rtc::scoped_refptr<RTCStatsCollectorCallbackImpl>
+RTCStatsCollectorCallbackImpl::Create(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    std::unique_ptr<blink::WebRTCStatsReportCallback> callback) {
+  return rtc::scoped_refptr<RTCStatsCollectorCallbackImpl>(
+      new rtc::RefCountedObject<RTCStatsCollectorCallbackImpl>(
+          std::move(main_thread), callback.release()));
+}
+
+RTCStatsCollectorCallbackImpl::RTCStatsCollectorCallbackImpl(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    blink::WebRTCStatsReportCallback* callback)
+    : main_thread_(std::move(main_thread)), callback_(callback) {}
+
+RTCStatsCollectorCallbackImpl::~RTCStatsCollectorCallbackImpl() {
+  DCHECK(!callback_);
+}
+
+void RTCStatsCollectorCallbackImpl::OnStatsDelivered(
+    const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
+  main_thread_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &RTCStatsCollectorCallbackImpl::OnStatsDeliveredOnMainThread, this,
+          report));
+}
+
+void RTCStatsCollectorCallbackImpl::OnStatsDeliveredOnMainThread(
+    rtc::scoped_refptr<const webrtc::RTCStatsReport> report) {
+  DCHECK(main_thread_->BelongsToCurrentThread());
+  DCHECK(report);
+  DCHECK(callback_);
+  callback_->OnStatsDelivered(std::unique_ptr<blink::WebRTCStatsReport>(
+      new RTCStatsReport(base::WrapRefCounted(report.get()))));
+  // Make sure the callback is destroyed in the main thread as well.
+  callback_.reset();
+}
+
 void WhitelistStatsForTesting(const char* type) {
   GetStatsWhitelist()->WhitelistStatsForTesting(type);
 }
diff --git a/content/renderer/media/webrtc/rtc_stats.h b/content/renderer/media/webrtc/rtc_stats.h
index 006aa2e9..4e9e50e 100644
--- a/content/renderer/media/webrtc/rtc_stats.h
+++ b/content/renderer/media/webrtc/rtc_stats.h
@@ -6,9 +6,11 @@
 #define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_STATS_H_
 
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebRTCStats.h"
 #include "third_party/webrtc/api/stats/rtcstats.h"
+#include "third_party/webrtc/api/stats/rtcstatscollectorcallback.h"
 #include "third_party/webrtc/api/stats/rtcstatsreport.h"
 
 namespace content {
@@ -85,6 +87,32 @@
   const webrtc::RTCStatsMemberInterface* const member_;
 };
 
+// A stats collector callback.
+// It is invoked on the WebRTC signaling thread and will post a task to invoke
+// |callback| on the thread given in the |main_thread| argument.
+// The argument to the callback will be a |blink::WebRTCStatsReport|.
+class RTCStatsCollectorCallbackImpl : public webrtc::RTCStatsCollectorCallback {
+ public:
+  static rtc::scoped_refptr<RTCStatsCollectorCallbackImpl> Create(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      std::unique_ptr<blink::WebRTCStatsReportCallback> callback);
+
+  void OnStatsDelivered(
+      const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override;
+
+ protected:
+  RTCStatsCollectorCallbackImpl(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      blink::WebRTCStatsReportCallback* callback);
+  ~RTCStatsCollectorCallbackImpl() override;
+
+  void OnStatsDeliveredOnMainThread(
+      rtc::scoped_refptr<const webrtc::RTCStatsReport> report);
+
+  const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
+  std::unique_ptr<blink::WebRTCStatsReportCallback> callback_;
+};
+
 CONTENT_EXPORT void WhitelistStatsForTesting(const char* type);
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
index 63d13f8..28d6c17 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
@@ -108,9 +108,15 @@
     return base::WrapUnique(
         new AdapterRef(this, AdapterRef::Type::kLocal, *adapter_ptr));
   }
-  scoped_refptr<WebRtcMediaStreamTrackAdapter> new_adapter =
-      WebRtcMediaStreamTrackAdapter::CreateLocalTrackAdapter(
-          factory_, main_thread_, web_track);
+  scoped_refptr<WebRtcMediaStreamTrackAdapter> new_adapter;
+  {
+    // Do not hold |lock_| while creating the adapter in case that operation
+    // synchronizes with the signaling thread. If we do and the signaling thread
+    // is blocked waiting for |lock_| we end up in a deadlock.
+    base::AutoUnlock scoped_unlock(lock_);
+    new_adapter = WebRtcMediaStreamTrackAdapter::CreateLocalTrackAdapter(
+        factory_, main_thread_, web_track);
+  }
   DCHECK(new_adapter->is_initialized());
   local_track_adapters_.Insert(web_track.UniqueId(), new_adapter);
   local_track_adapters_.SetSecondaryKey(web_track.UniqueId(),
@@ -161,9 +167,15 @@
     return base::WrapUnique(
         new AdapterRef(this, AdapterRef::Type::kRemote, *adapter_ptr));
   }
-  scoped_refptr<WebRtcMediaStreamTrackAdapter> new_adapter =
-      WebRtcMediaStreamTrackAdapter::CreateRemoteTrackAdapter(
-          factory_, main_thread_, webrtc_track);
+  scoped_refptr<WebRtcMediaStreamTrackAdapter> new_adapter;
+  {
+    // Do not hold |lock_| while creating the adapter in case that operation
+    // synchronizes with the main thread. If we do and the main thread is
+    // blocked waiting for |lock_| we end up in a deadlock.
+    base::AutoUnlock scoped_unlock(lock_);
+    new_adapter = WebRtcMediaStreamTrackAdapter::CreateRemoteTrackAdapter(
+        factory_, main_thread_, webrtc_track);
+  }
   remote_track_adapters_.Insert(webrtc_track.get(), new_adapter);
   // The new adapter is initialized in a post to the main thread. As soon as it
   // is initialized we map its |webrtc_track| to the |remote_track_adapters_|
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
index d531eae..68d0689f 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/memory/ref_counted.h"
+#include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/scoped_task_environment.h"
@@ -33,6 +34,10 @@
 
   void TearDown() override { blink::WebHeap::CollectAllGarbageForTesting(); }
 
+  scoped_refptr<base::SingleThreadTaskRunner> signaling_thread() const {
+    return dependency_factory_->GetWebRtcSignalingThread();
+  }
+
   blink::WebMediaStreamTrack CreateLocalTrack(const std::string& id) {
     blink::WebMediaStreamSource web_source;
     web_source.Initialize(
@@ -53,7 +58,7 @@
       webrtc::MediaStreamTrackInterface* webrtc_track) {
     DCHECK(main_thread_->BelongsToCurrentThread());
     std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> adapter;
-    dependency_factory_->GetWebRtcSignalingThread()->PostTask(
+    signaling_thread()->PostTask(
         FROM_HERE,
         base::BindOnce(&WebRtcMediaStreamTrackAdapterMapTest::
                            GetOrCreateRemoteTrackAdapterOnSignalingThread,
@@ -66,8 +71,7 @@
   void GetOrCreateRemoteTrackAdapterOnSignalingThread(
       webrtc::MediaStreamTrackInterface* webrtc_track,
       std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>* adapter) {
-    DCHECK(dependency_factory_->GetWebRtcSignalingThread()
-               ->BelongsToCurrentThread());
+    DCHECK(signaling_thread()->BelongsToCurrentThread());
     *adapter = map_->GetOrCreateRemoteTrackAdapter(webrtc_track);
   }
 
@@ -78,7 +82,7 @@
     base::WaitableEvent waitable_event(
         base::WaitableEvent::ResetPolicy::MANUAL,
         base::WaitableEvent::InitialState::NOT_SIGNALED);
-    dependency_factory_->GetWebRtcSignalingThread()->PostTask(
+    signaling_thread()->PostTask(
         FROM_HERE, base::BindOnce(&WebRtcMediaStreamTrackAdapterMapTest::
                                       RunMessageLoopUntilIdleOnSignalingThread,
                                   base::Unretained(this), &waitable_event));
@@ -88,8 +92,7 @@
 
   void RunMessageLoopUntilIdleOnSignalingThread(
       base::WaitableEvent* waitable_event) {
-    DCHECK(dependency_factory_->GetWebRtcSignalingThread()
-               ->BelongsToCurrentThread());
+    DCHECK(signaling_thread()->BelongsToCurrentThread());
     base::RunLoop().RunUntilIdle();
     waitable_event->Signal();
   }
@@ -213,4 +216,99 @@
   EXPECT_EQ(nullptr, map_->GetRemoteTrackAdapter(webrtc_track.get()));
 }
 
+// Continuously calls GetOrCreateLocalTrackAdapter() on the main thread and
+// GetOrCreateRemoteTrackAdapter() on the signaling thread hoping to hit
+// deadlocks if the operations were to synchronize with the other thread while
+// holding the lock.
+//
+// Note that this deadlock has been notoriously difficult to reproduce. This
+// test is added as an attempt to guard against this type of regression, but do
+// not trust that if this test passes there is no risk of deadlock.
+class WebRtcMediaStreamTrackAdapterMapStressTest
+    : public WebRtcMediaStreamTrackAdapterMapTest {
+ public:
+  WebRtcMediaStreamTrackAdapterMapStressTest()
+      : WebRtcMediaStreamTrackAdapterMapTest(), remaining_iterations_(0u) {}
+
+  void RunStressTest(size_t iterations) {
+    base::RunLoop run_loop;
+    remaining_iterations_ = iterations;
+    PostSignalingThreadLoop();
+    MainThreadLoop(&run_loop);
+    run_loop.Run();
+    // The run loop ensures all operations have began executing, but does not
+    // guarantee that all of them are complete, i.e. that track adapters have
+    // been fully initialized and subequently disposed. For that we need to run
+    // until idle or else we may tear down the test prematurely.
+    RunMessageLoopsUntilIdle();
+  }
+
+  void MainThreadLoop(base::RunLoop* run_loop) {
+    for (size_t i = 0u; i < 5u; ++i) {
+      map_->GetOrCreateLocalTrackAdapter(CreateLocalTrack("local_track_id"));
+    }
+    if (--remaining_iterations_ > 0) {
+      PostSignalingThreadLoop();
+      PostMainThreadLoop(run_loop);
+    } else {
+      // We are now done, but there may still be operations pending to execute
+      // on signaling thread so we perform Quit() in a post to the signaling
+      // thread. This ensures that Quit() is called after all operations have
+      // began executing (but does not guarantee that all operations have
+      // completed).
+      signaling_thread()->PostTask(
+          FROM_HERE,
+          base::BindOnce(&WebRtcMediaStreamTrackAdapterMapStressTest::
+                             QuitRunLoopOnSignalingThread,
+                         base::Unretained(this), base::Unretained(run_loop)));
+    }
+  }
+
+  void PostMainThreadLoop(base::RunLoop* run_loop) {
+    main_thread_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &WebRtcMediaStreamTrackAdapterMapStressTest::MainThreadLoop,
+            base::Unretained(this), base::Unretained(run_loop)));
+  }
+
+  void SignalingThreadLoop() {
+    std::vector<std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>>
+        track_refs;
+    for (size_t i = 0u; i < 5u; ++i) {
+      track_refs.push_back(map_->GetOrCreateRemoteTrackAdapter(
+          MockWebRtcAudioTrack::Create("remote_track_id")));
+    }
+    main_thread_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&WebRtcMediaStreamTrackAdapterMapStressTest::
+                           DestroyAdapterRefsOnMainThread,
+                       base::Unretained(this), std::move(track_refs)));
+  }
+
+  void PostSignalingThreadLoop() {
+    signaling_thread()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &WebRtcMediaStreamTrackAdapterMapStressTest::SignalingThreadLoop,
+            base::Unretained(this)));
+  }
+
+  void DestroyAdapterRefsOnMainThread(
+      std::vector<std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>>
+          track_refs) {}
+
+  void QuitRunLoopOnSignalingThread(base::RunLoop* run_loop) {
+    run_loop->Quit();
+  }
+
+ private:
+  size_t remaining_iterations_;
+};
+
+TEST_F(WebRtcMediaStreamTrackAdapterMapStressTest, StressTest) {
+  const size_t kNumStressTestIterations = 1000u;
+  RunStressTest(kNumStressTestIterations);
+}
+
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 21d09e8..72f1184b 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2527,7 +2527,7 @@
     converter.SetDateAllowed(true);
     converter.SetRegExpAllowed(true);
     base::string16 data;
-    data.resize(params.message->data.encoded_message.length() /
+    data.resize(params.message->data.encoded_message.size() /
                 sizeof(base::char16));
     std::memcpy(&data[0], params.message->data.encoded_message.data(),
                 data.length() * sizeof(base::char16));
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 6ab2e6a1..a6a14b8e 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -895,7 +895,7 @@
   settings->SetReportScreenSizeInPhysicalPixelsQuirk(
       prefs.report_screen_size_in_physical_pixels_quirk);
   settings->SetShouldReuseGlobalForUnownedMainFrame(
-      prefs.resue_global_for_unowned_main_frame);
+      prefs.reuse_global_for_unowned_main_frame);
   settings->SetPreferHiddenVolumeControls(true);
   settings->SetSpellCheckEnabledByDefault(prefs.spellcheck_enabled_by_default);
 
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index edc0bba..2bac8d1ae 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -608,7 +608,6 @@
 
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     DCHECK(!response_);
     DCHECK(!downloaded_file);
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 7102a1d..c578eb7 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -79,11 +79,10 @@
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(
       const network::ResourceResponseHead& response_head,
-      const base::Optional<net::SSLInfo>& ssl_info,
       network::mojom::DownloadedTempFilePtr downloaded_file) override {
     DCHECK(url_loader_client_.is_bound());
     url_loader_client_->OnReceiveResponse(
-        rewrite_header_callback_.Run(response_head), ssl_info,
+        rewrite_header_callback_.Run(response_head),
         std::move(downloaded_file));
   }
 
@@ -482,7 +481,6 @@
   status_ = Status::kSentHeader;
   // TODO(kinuko): Fill the ssl_info.
   url_loader_client_->OnReceiveResponse(response_head_,
-                                        base::nullopt /* ssl_info_ */,
                                         nullptr /* downloaded_file */);
 }
 
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index f3403720..b6e74b89 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -55,7 +55,7 @@
     network::ResourceResponseHead response;
     response.headers = info.headers;
     response.headers->GetMimeType(&response.mime_type);
-    client->OnReceiveResponse(response, base::nullopt, nullptr);
+    client->OnReceiveResponse(response, nullptr);
 
     std::string body = "this body came from the network";
     uint32_t bytes_written = body.size();
diff --git a/content/shell/android/java/src/org/chromium/content_shell/Shell.java b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
index fd0f09e..dec3c6b 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/Shell.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
@@ -125,6 +125,7 @@
         mWindow = null;
         mNativeShell = 0;
         mContentViewCore.destroy();
+        mWebContents = null;
     }
 
     /**
@@ -303,11 +304,11 @@
         mViewAndroidDelegate = new ShellViewAndroidDelegate(cv);
         mContentViewCore = (ContentViewCoreImpl) ContentViewCore.create(
                 context, "", webContents, mViewAndroidDelegate, cv, mWindow);
-        mWebContents = mContentViewCore.getWebContents();
+        mWebContents = webContents;
         SelectionPopupController controller = SelectionPopupController.fromWebContents(webContents);
         controller.setActionModeCallback(defaultActionCallback());
         mNavigationController = mWebContents.getNavigationController();
-        if (getParent() != null) mContentViewCore.onShow();
+        if (getParent() != null) mWebContents.onShow();
         if (mWebContents.getVisibleUrl() != null) {
             mUrlTextView.setText(mWebContents.getVisibleUrl());
         }
@@ -316,7 +317,7 @@
                         FrameLayout.LayoutParams.MATCH_PARENT,
                         FrameLayout.LayoutParams.MATCH_PARENT));
         cv.requestFocus();
-        mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
+        mContentViewRenderView.setCurrentWebContents(mWebContents);
     }
 
     /**
diff --git a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
index 4fc7c35e..5c3ecb3a 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
@@ -13,7 +13,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.ContentViewRenderView;
-import org.chromium.content_public.browser.ContentViewCore;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -109,10 +109,10 @@
         addView(shellView, new FrameLayout.LayoutParams(
                 FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
         mActiveShell = shellView;
-        ContentViewCore contentViewCore = mActiveShell.getContentViewCore();
-        if (contentViewCore != null) {
-            mContentViewRenderView.setCurrentContentViewCore(contentViewCore);
-            contentViewCore.onShow();
+        WebContents webContents = mActiveShell.getWebContents();
+        if (webContents != null) {
+            mContentViewRenderView.setCurrentWebContents(webContents);
+            webContents.onShow();
         }
     }
 
@@ -120,8 +120,8 @@
     private void removeShell(Shell shellView) {
         if (shellView == mActiveShell) mActiveShell = null;
         if (shellView.getParent() == null) return;
-        ContentViewCore contentViewCore = shellView.getContentViewCore();
-        if (contentViewCore != null) contentViewCore.onHide();
+        WebContents webContents = shellView.getWebContents();
+        if (webContents != null) webContents.onHide();
         shellView.setContentViewRenderView(null);
         removeView(shellView);
     }
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
index 6923436f..69e1e44e 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
@@ -18,7 +18,7 @@
 import org.chromium.base.library_loader.Linker;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.content.browser.BrowserStartupController;
-import org.chromium.content_public.browser.ContentViewCore;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_shell.Shell;
 import org.chromium.content_shell.ShellManager;
 import org.chromium.ui.base.ActivityWindowAndroid;
@@ -147,16 +147,16 @@
     protected void onStop() {
         super.onStop();
 
-        ContentViewCore contentViewCore = getActiveContentViewCore();
-        if (contentViewCore != null) contentViewCore.onHide();
+        WebContents webContents = getActiveWebContents();
+        if (webContents != null) webContents.onHide();
     }
 
     @Override
     protected void onStart() {
         super.onStart();
 
-        ContentViewCore contentViewCore = getActiveContentViewCore();
-        if (contentViewCore != null) contentViewCore.onShow();
+        WebContents webContents = getActiveWebContents();
+        if (webContents != null) webContents.onHide();
     }
 
     @Override
@@ -170,19 +170,12 @@
     }
 
     /**
-     * @return The {@link ContentViewCore} owned by the currently visible {@link Shell} or null if
+     * @return The {@link WebContents} owned by the currently visible {@link Shell} or null if
      *         one is not showing.
      */
-    public ContentViewCore getActiveContentViewCore() {
-        if (mShellManager == null) {
-            return null;
-        }
-
+    public WebContents getActiveWebContents() {
+        if (mShellManager == null) return null;
         Shell shell = mShellManager.getActiveShell();
-        if (shell == null) {
-            return null;
-        }
-
-        return shell.getContentViewCore();
+        return shell != null ? shell.getWebContents() : null;
     }
 }
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
index 274956f..fb3da9b 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -185,8 +185,8 @@
     protected void onStart() {
         super.onStart();
 
-        ContentViewCore contentViewCore = getActiveContentViewCore();
-        if (contentViewCore != null) contentViewCore.onShow();
+        WebContents webContents = getActiveWebContents();
+        if (webContents != null) webContents.onShow();
     }
 
     @Override
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index a23315f8..fddbbc16 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -382,16 +382,23 @@
     const bool automatic_flushes = false;
     const bool support_locking = false;
 
-    auto context_provider =
-        base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
-            gpu_channel_, gpu_memory_buffer_manager_, kGpuStreamIdDefault,
-            kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle,
-            GURL("chrome://gpu/"
-                 "LayoutTestDependenciesImpl::CreateOutputSurface"),
-            automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
-            attributes, nullptr,
-            ui::command_buffer_metrics::OFFSCREEN_CONTEXT_FOR_TESTING);
-    context_provider->BindToCurrentThread();
+    scoped_refptr<viz::ContextProvider> context_provider;
+
+    gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure;
+    while (context_result != gpu::ContextResult::kSuccess) {
+      context_provider = base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+          gpu_channel_, gpu_memory_buffer_manager_, kGpuStreamIdDefault,
+          kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle,
+          GURL("chrome://gpu/"
+               "LayoutTestDependenciesImpl::CreateOutputSurface"),
+          automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
+          attributes, nullptr,
+          ui::command_buffer_metrics::OFFSCREEN_CONTEXT_FOR_TESTING);
+      context_result = context_provider->BindToCurrentThread();
+
+      // Layout tests can't recover from a fatal failure.
+      CHECK_NE(context_result, gpu::ContextResult::kFatalFailure);
+    }
 
     bool flipped_output_surface = false;
     return std::make_unique<cc::PixelTestOutputSurface>(
diff --git a/content/test/proxy_service_mojo_unittest.cc b/content/test/proxy_service_mojo_unittest.cc
index 56ab230..4376b9c 100644
--- a/content/test/proxy_service_mojo_unittest.cc
+++ b/content/test/proxy_service_mojo_unittest.cc
@@ -132,15 +132,16 @@
     mock_host_resolver_.rules()->AddRule("example.com", "1.2.3.4");
 
     fetcher_ = new net::MockPacFileFetcher;
-    proxy_resolution_service_ = network::CreateProxyServiceUsingMojoFactory(
-        test_mojo_proxy_resolver_factory_.CreateFactoryInterface(),
-        std::make_unique<net::ProxyConfigServiceFixed>(
-            net::ProxyConfigWithAnnotation(
-                net::ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl)),
-                TRAFFIC_ANNOTATION_FOR_TESTS)),
-        base::WrapUnique(fetcher_),
-        std::make_unique<net::DoNothingDhcpPacFileFetcher>(),
-        &mock_host_resolver_, &net_log_, &network_delegate_);
+    proxy_resolution_service_ =
+        network::CreateProxyResolutionServiceUsingMojoFactory(
+            test_mojo_proxy_resolver_factory_.CreateFactoryInterface(),
+            std::make_unique<net::ProxyConfigServiceFixed>(
+                net::ProxyConfigWithAnnotation(
+                    net::ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl)),
+                    TRAFFIC_ANNOTATION_FOR_TESTS)),
+            base::WrapUnique(fetcher_),
+            std::make_unique<net::DoNothingDhcpPacFileFetcher>(),
+            &mock_host_resolver_, &net_log_, &network_delegate_);
   }
 
   base::test::ScopedTaskEnvironment task_environment_;
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc
index 3a9e35d..d16b432 100644
--- a/content/test/test_navigation_url_loader.cc
+++ b/content/test/test_navigation_url_loader.cc
@@ -76,8 +76,7 @@
   GlobalRequestID global_id(child_id, ++request_id);
   delegate_->OnResponseStarted(
       response, network::mojom::URLLoaderClientEndpointsPtr(), std::move(body),
-      net::SSLInfo(), std::move(navigation_data), global_id, false, false,
-      base::nullopt);
+      std::move(navigation_data), global_id, false, false, base::nullopt);
 }
 
 TestNavigationURLLoader::~TestNavigationURLLoader() {}
diff --git a/content/test/test_navigation_url_loader_delegate.cc b/content/test/test_navigation_url_loader_delegate.cc
index edfa504..c4dd8b6 100644
--- a/content/test/test_navigation_url_loader_delegate.cc
+++ b/content/test/test_navigation_url_loader_delegate.cc
@@ -61,7 +61,6 @@
     const scoped_refptr<network::ResourceResponse>& response,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<StreamHandle> body,
-    const net::SSLInfo& ssl_info,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
     bool is_download,
@@ -70,7 +69,8 @@
   response_ = response;
   url_loader_client_endpoints_ = std::move(url_loader_client_endpoints);
   body_ = std::move(body);
-  ssl_info_ = ssl_info;
+  if (response->head.ssl_info.has_value())
+    ssl_info_ = *response->head.ssl_info;
   is_download_ = is_download;
   if (response_started_)
     response_started_->Quit();
diff --git a/content/test/test_navigation_url_loader_delegate.h b/content/test/test_navigation_url_loader_delegate.h
index 3d83d7c..55600871 100644
--- a/content/test/test_navigation_url_loader_delegate.h
+++ b/content/test/test_navigation_url_loader_delegate.h
@@ -64,7 +64,6 @@
       const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<StreamHandle> body,
-      const net::SSLInfo& ssl_info,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& request_id,
       bool is_download,
diff --git a/device/fido/u2f_register_unittest.cc b/device/fido/u2f_register_unittest.cc
index 716e4c6f..e7539f84 100644
--- a/device/fido/u2f_register_unittest.cc
+++ b/device/fido/u2f_register_unittest.cc
@@ -343,7 +343,8 @@
       0x07, 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
       0x09, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
       0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00,
-      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
+      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01, 0x00,
+      0x00,
   };
 
   constexpr uint8_t kRegisterApduCommandWithAttestation[] = {
@@ -359,6 +360,8 @@
       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01, 0x02, 0x03,
       0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
+      // Max response length
+      0x00, 0x00,
   };
 
   U2fRegister register_request(nullptr /* connector */, protocols_,
diff --git a/device/fido/u2f_request.cc b/device/fido/u2f_request.cc
index 65e8c77..0228f38 100644
--- a/device/fido/u2f_request.cc
+++ b/device/fido/u2f_request.cc
@@ -97,6 +97,7 @@
   command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kSign));
   command.set_p1(is_check_only_sign ? kP1CheckOnly : kP1TupRequiredConsumed);
   command.set_data(data);
+  command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
   return command.GetEncodedCommand();
 }
 
@@ -114,6 +115,7 @@
   command.set_p1(kP1TupRequiredConsumed |
                  (is_individual_attestation ? kP1IndividualAttestation : 0));
   command.set_data(data);
+  command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
   return command.GetEncodedCommand();
 }
 
diff --git a/device/fido/u2f_sign_unittest.cc b/device/fido/u2f_sign_unittest.cc
index eace420..fbd582c 100644
--- a/device/fido/u2f_sign_unittest.cc
+++ b/device/fido/u2f_sign_unittest.cc
@@ -179,7 +179,9 @@
       // Key Handle
       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00,
       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
-      0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01
+      0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
+      // Max response length
+      0x00, 0x00,
       // clang-format on
   };
 
@@ -209,7 +211,9 @@
       // Key Handle
       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00,
       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
-      0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01
+      0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x01,
+      // Max response length
+      0x00, 0x00,
       // clang-format on
   };
 
diff --git a/extensions/browser/api/socket/udp_socket.cc b/extensions/browser/api/socket/udp_socket.cc
index 3a55686..094508e3 100644
--- a/extensions/browser/api/socket/udp_socket.cc
+++ b/extensions/browser/api/socket/udp_socket.cc
@@ -127,12 +127,11 @@
   base::span<const uint8_t> data(
       reinterpret_cast<const uint8_t*>(io_buffer->data()),
       static_cast<size_t>(io_buffer_size));
-  socket_->Send(
-      data,
-      net::MutableNetworkTrafficAnnotationTag(
-          Socket::GetNetworkTrafficAnnotationTag()),
-      base::BindOnce(&UDPSocket::OnWriteOrSendToCompleted,
-                     base::Unretained(this), callback, data.length()));
+  socket_->Send(data,
+                net::MutableNetworkTrafficAnnotationTag(
+                    Socket::GetNetworkTrafficAnnotationTag()),
+                base::BindOnce(&UDPSocket::OnWriteOrSendToCompleted,
+                               base::Unretained(this), callback, data.size()));
   return net::ERR_IO_PENDING;
 }
 
@@ -181,7 +180,7 @@
       net::MutableNetworkTrafficAnnotationTag(
           Socket::GetNetworkTrafficAnnotationTag()),
       base::BindOnce(&UDPSocket::OnWriteOrSendToCompleted,
-                     base::Unretained(this), callback, data.length()));
+                     base::Unretained(this), callback, data.size()));
 }
 
 bool UDPSocket::IsConnected() {
@@ -231,18 +230,18 @@
   }
 
   scoped_refptr<net::IOBuffer> io_buffer =
-      new net::IOBuffer(data.value().length());
-  memcpy(io_buffer->data(), data.value().data(), data.value().length());
+      new net::IOBuffer(data.value().size());
+  memcpy(io_buffer->data(), data.value().data(), data.value().size());
 
   if (!read_callback_.is_null()) {
     base::ResetAndReturn(&read_callback_)
-        .Run(data.value().length(), io_buffer, false /* socket_destroying */);
+        .Run(data.value().size(), io_buffer, false /* socket_destroying */);
     return;
   }
 
   IPEndPointToStringAndPort(src_addr.value(), &ip, &port);
   base::ResetAndReturn(&recv_from_callback_)
-      .Run(data.value().length(), io_buffer, false /* socket_destroying */, ip,
+      .Run(data.value().size(), io_buffer, false /* socket_destroying */, ip,
            port);
 }
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index aed8c02..466a63d1 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -121,12 +121,11 @@
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnReceiveResponse(
     const network::ResourceResponseHead& head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
   current_response_ = head;
   HandleResponseOrRedirectHeaders(base::BindRepeating(
       &InProgressRequest::ContinueToResponseStarted, weak_factory_.GetWeakPtr(),
-      ssl_info, base::Passed(&downloaded_file)));
+      base::Passed(&downloaded_file)));
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnReceiveRedirect(
@@ -288,7 +287,6 @@
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::
     ContinueToResponseStarted(
-        const base::Optional<net::SSLInfo>& ssl_info,
         network::mojom::DownloadedTempFilePtr downloaded_file,
         int error_code) {
   if (error_code != net::OK) {
@@ -338,7 +336,7 @@
 
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
       factory_->browser_context_, factory_->info_map_, &info_.value(), net::OK);
-  target_client_->OnReceiveResponse(current_response_, ssl_info,
+  target_client_->OnReceiveResponse(current_response_,
                                     std::move(downloaded_file));
 }
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 1dc89f5..c3c8283b 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -70,7 +70,6 @@
     // network::mojom::URLLoaderClient:
     void OnReceiveResponse(
         const network::ResourceResponseHead& head,
-        const base::Optional<net::SSLInfo>& ssl_info,
         network::mojom::DownloadedTempFilePtr downloaded_file) override;
     void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                            const network::ResourceResponseHead& head) override;
@@ -88,7 +87,6 @@
     void ContinueToBeforeSendHeaders(int error_code);
     void ContinueToSendHeaders(int error_code);
     void ContinueToResponseStarted(
-        const base::Optional<net::SSLInfo>& ssl_info,
         network::mojom::DownloadedTempFilePtr downloaded_file,
         int error_code);
     void ContinueToBeforeRedirect(const net::RedirectInfo& redirect_info,
diff --git a/extensions/browser/content_verifier/content_hash.cc b/extensions/browser/content_verifier/content_hash.cc
index 31cd1db..e83f179 100644
--- a/extensions/browser/content_verifier/content_hash.cc
+++ b/extensions/browser/content_verifier/content_hash.cc
@@ -28,7 +28,8 @@
 
 using SortedFilePathSet = std::set<base::FilePath>;
 
-bool WriteFile(const base::FilePath& destination, const std::string& content) {
+bool CreateDirAndWriteFile(const base::FilePath& destination,
+                           const std::string& content) {
   base::AssertBlockingAllowed();
   DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
   base::FilePath dir = destination.DirName();
@@ -196,7 +197,7 @@
 
   base::FilePath destination =
       file_util::GetVerifiedContentsPath(key.extension_root);
-  if (!WriteFile(destination, *fetched_contents)) {
+  if (!CreateDirAndWriteFile(destination, *fetched_contents)) {
     LOG(ERROR) << "Error writing computed_hashes.json at " << destination;
     ContentHash::DispatchFetchFailure(key, std::move(created_callback),
                                       is_cancelled);
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index c6cd52d..9bb4be9 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -847,7 +847,7 @@
         return;
       }
 
-      client->OnReceiveResponse(head, base::nullopt, nullptr);
+      client->OnReceiveResponse(head, nullptr);
       client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
       client->OnComplete(network::URLLoaderCompletionStatus(net::OK));
       return;
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 10f329d6..d145bdc 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -575,6 +575,12 @@
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = info.Holder()->CreationContext();
 
+  // Force binding creation in the owning context (even if another context is
+  // calling in). This is also important to ensure that objects created through
+  // the initialization process are all instantiated for the owning context.
+  // See https://crbug.com/819968.
+  v8::Context::Scope context_scope(context);
+
   // We use info.Data() to store a real name here instead of using the provided
   // one to handle any weirdness from the caller (non-existent strings, etc).
   v8::Local<v8::String> api_name = info.Data().As<v8::String>();
diff --git a/extensions/renderer/native_extension_bindings_system_test_base.cc b/extensions/renderer/native_extension_bindings_system_test_base.cc
index 49e53a01..84db583 100644
--- a/extensions/renderer/native_extension_bindings_system_test_base.cc
+++ b/extensions/renderer/native_extension_bindings_system_test_base.cc
@@ -93,7 +93,10 @@
                    [context](ScriptContext* script_context) {
                      return script_context->v8_context() == context;
                    });
-  ASSERT_TRUE(iter != raw_script_contexts_.end());
+  if (iter == raw_script_contexts_.end()) {
+    ASSERT_TRUE(allow_unregistered_contexts_);
+    return;
+  }
   bindings_system_->WillReleaseScriptContext(*iter);
   script_context_set_->Remove(*iter);
   raw_script_contexts_.erase(iter);
diff --git a/extensions/renderer/native_extension_bindings_system_test_base.h b/extensions/renderer/native_extension_bindings_system_test_base.h
index 6f41a8e..0641f11b 100644
--- a/extensions/renderer/native_extension_bindings_system_test_base.h
+++ b/extensions/renderer/native_extension_bindings_system_test_base.h
@@ -137,6 +137,9 @@
   StringSourceMap* source_map() { return &source_map_; }
   TestIPCMessageSender* ipc_message_sender() { return ipc_message_sender_; }
   ScriptContextSet* script_context_set() { return script_context_set_.get(); }
+  void set_allow_unregistered_contexts(bool allow_unregistered_contexts) {
+    allow_unregistered_contexts_ = allow_unregistered_contexts;
+  }
 
  private:
   ExtensionIdSet extension_ids_;
@@ -152,6 +155,10 @@
   StringSourceMap source_map_;
   TestExtensionsRendererClient renderer_client_;
 
+  // True if we allow some v8::Contexts to avoid registration as a
+  // ScriptContext.
+  bool allow_unregistered_contexts_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(NativeExtensionBindingsSystemUnittest);
 };
 
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index d187e39..7ac9c1c 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -1068,4 +1068,54 @@
   EXPECT_TRUE(property->IsUndefined());
 }
 
+// Test that API initialization happens in the owning context.
+TEST_F(NativeExtensionBindingsSystemUnittest, APIIsInitializedByOwningContext) {
+  // Attach custom JS hooks.
+  const char kCustomBinding[] =
+      R"(this.apiBridge = apiBridge;
+         apiBridge.registerCustomHook(() => {});)";
+  source_map()->RegisterModule("idle", kCustomBinding);
+
+  scoped_refptr<Extension> extension =
+      ExtensionBuilder("foo").AddPermission("idle").Build();
+  RegisterExtension(extension);
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  ScriptContext* script_context = CreateScriptContext(
+      context, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT);
+  script_context->set_url(extension->url());
+
+  bindings_system()->UpdateBindingsForContext(script_context);
+
+  {
+    // Create a second, uninitialized context, which will trigger the
+    // construction of chrome.idle in the first context.
+    set_allow_unregistered_contexts(true);
+    v8::Local<v8::Context> second_context = AddContext();
+
+    v8::Local<v8::Function> get_idle = FunctionFromString(
+        second_context, "(function(chrome) { chrome.idle; })");
+    v8::Local<v8::Value> chrome =
+        context->Global()
+            ->Get(context, gin::StringToV8(isolate(), "chrome"))
+            .ToLocalChecked();
+    ASSERT_TRUE(chrome->IsObject());
+
+    v8::Context::Scope context_scope(second_context);
+    v8::Local<v8::Value> args[] = {chrome};
+    RunFunction(get_idle, second_context, arraysize(args), args);
+  }
+
+  // The apiBridge should have been created in the owning (original) context,
+  // even though the initialization was triggered by the second context.
+  v8::Local<v8::Value> api_bridge =
+      context->Global()
+          ->Get(context, gin::StringToV8(isolate(), "apiBridge"))
+          .ToLocalChecked();
+  ASSERT_TRUE(api_bridge->IsObject());
+  EXPECT_EQ(context, api_bridge.As<v8::Object>()->CreationContext());
+}
+
 }  // namespace extensions
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index 2684e608..0301ac2 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -25,6 +25,8 @@
     "function_template.cc",
     "function_template.h",
     "gin_export.h",
+    "gin_features.cc",
+    "gin_features.h",
     "handle.h",
     "interceptor.cc",
     "interceptor.h",
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
new file mode 100644
index 0000000..a487e25
--- /dev/null
+++ b/gin/gin_features.cc
@@ -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.
+
+#include "gin/gin_features.h"
+
+namespace features {
+
+// Enables optimization of JavaScript in V8.
+const base::Feature kV8OptimizeJavascript{"V8OptimizeJavascript",
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
+
+}  // namespace features
diff --git a/gin/gin_features.h b/gin/gin_features.h
new file mode 100644
index 0000000..58bb433
--- /dev/null
+++ b/gin/gin_features.h
@@ -0,0 +1,17 @@
+// 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 GIN_GIN_FEATURES_H_
+#define GIN_GIN_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "gin/gin_export.h"
+
+namespace features {
+
+GIN_EXPORT extern const base::Feature kV8OptimizeJavascript;
+
+}  // namespace features
+
+#endif  // GIN_GIN_FEATURES_H_
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 7c1d44ce..02d4b1c 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -25,6 +25,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "gin/gin_features.h"
 
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
 #if defined(OS_ANDROID)
@@ -242,6 +243,14 @@
 
   v8::V8::InitializePlatform(V8Platform::Get());
 
+  if (base::FeatureList::IsEnabled(features::kV8OptimizeJavascript)) {
+    static const char optimize[] = "--opt";
+    v8::V8::SetFlagsFromString(optimize, sizeof(optimize) - 1);
+  } else {
+    static const char no_optimize[] = "--no-opt";
+    v8::V8::SetFlagsFromString(no_optimize, sizeof(no_optimize) - 1);
+  }
+
   if (IsolateHolder::kStrictMode == mode) {
     static const char use_strict[] = "--use_strict";
     v8::V8::SetFlagsFromString(use_strict, sizeof(use_strict) - 1);
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index f360d31..401f6a8 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -289,6 +289,8 @@
     "lib/browser/headless_network_conditions.h",
     "lib/browser/headless_network_delegate.cc",
     "lib/browser/headless_network_delegate.h",
+    "lib/browser/headless_network_transaction_factory.cc",
+    "lib/browser/headless_network_transaction_factory.h",
     "lib/browser/headless_permission_manager.cc",
     "lib/browser/headless_permission_manager.h",
     "lib/browser/headless_platform_event_source.cc",
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index d86a0f73..eb14f1b 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -403,6 +403,14 @@
     observer.UrlRequestFailed(request, net_error, devtools_status);
 }
 
+void HeadlessBrowserContextImpl::NotifyMetadataForResource(const GURL& url,
+                                                           net::IOBuffer* buf,
+                                                           int buf_len) {
+  base::AutoLock lock(observers_lock_);
+  for (auto& observer : observers_)
+    observer.OnMetadataForResource(url, buf, buf_len);
+}
+
 void HeadlessBrowserContextImpl::SetNetworkConditions(
     HeadlessNetworkConditions conditions) {
   network_conditions_ = conditions;
@@ -531,6 +539,13 @@
   return *this;
 }
 
+HeadlessBrowserContext::Builder&
+HeadlessBrowserContext::Builder::SetCaptureResourceMetadata(
+    bool capture_resource_metadata) {
+  options_->capture_resource_metadata_ = capture_resource_metadata;
+  return *this;
+}
+
 HeadlessBrowserContext* HeadlessBrowserContext::Builder::Build() {
   if (!mojo_bindings_.empty()) {
     // Unless you know what you're doing it's unsafe to allow http/https for a
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h
index 7c27e9b..a032d4cd 100644
--- a/headless/lib/browser/headless_browser_context_impl.h
+++ b/headless/lib/browser/headless_browser_context_impl.h
@@ -120,6 +120,10 @@
                               int net_error,
                               DevToolsStatus devtools_status);
 
+  void NotifyMetadataForResource(const GURL& url,
+                                 net::IOBuffer* buf,
+                                 int buf_len);
+
   void SetNetworkConditions(HeadlessNetworkConditions conditions);
   HeadlessNetworkConditions GetNetworkConditions() override;
 
diff --git a/headless/lib/browser/headless_browser_context_options.cc b/headless/lib/browser/headless_browser_context_options.cc
index 225b3720..84fade9 100644
--- a/headless/lib/browser/headless_browser_context_options.cc
+++ b/headless/lib/browser/headless_browser_context_options.cc
@@ -84,6 +84,11 @@
                                browser_options_->block_new_web_contents);
 }
 
+bool HeadlessBrowserContextOptions::capture_resource_metadata() const {
+  return ReturnOverriddenValue(capture_resource_metadata_,
+                               browser_options_->capture_resource_metadata);
+}
+
 base::Optional<base::Time> HeadlessBrowserContextOptions::initial_virtual_time()
     const {
   if (initial_virtual_time_)
diff --git a/headless/lib/browser/headless_browser_context_options.h b/headless/lib/browser/headless_browser_context_options.h
index 5dd6f78c..80c6099 100644
--- a/headless/lib/browser/headless_browser_context_options.h
+++ b/headless/lib/browser/headless_browser_context_options.h
@@ -51,6 +51,9 @@
   // See HeadlessBrowser::Options::block_new_web_contents.
   bool block_new_web_contents() const;
 
+  // See HeadlessBrowser::Options::capture_resource_metadata.
+  bool capture_resource_metadata() const;
+
   // If set the renderer will be constructed with virtual time enabled and in it
   // base::Time::Now will be overridden to initially return this value.
   base::Optional<base::Time> initial_virtual_time() const;
@@ -92,6 +95,7 @@
   base::Optional<bool> allow_cookies_;
   base::Optional<base::RepeatingCallback<void(WebPreferences*)>>
       override_web_preferences_callback_;
+  base::Optional<bool> capture_resource_metadata_;
 
   ProtocolHandlerMap protocol_handlers_;
 
diff --git a/headless/lib/browser/headless_network_transaction_factory.cc b/headless/lib/browser/headless_network_transaction_factory.cc
new file mode 100644
index 0000000..0e06b33
--- /dev/null
+++ b/headless/lib/browser/headless_network_transaction_factory.cc
@@ -0,0 +1,81 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "headless/lib/browser/headless_network_transaction_factory.h"
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "headless/lib/browser/headless_browser_context_impl.h"
+#include "net/http/http_cache_writers.h"
+#include "net/http/http_transaction.h"
+
+namespace headless {
+
+class HeadlessCacheBackendFactory : public net::HttpCache::BackendFactory {
+ public:
+  HeadlessCacheBackendFactory() {}
+  ~HeadlessCacheBackendFactory() override {}
+
+  int CreateBackend(net::NetLog* net_log,
+                    std::unique_ptr<disk_cache::Backend>* backend,
+                    const net::CompletionCallback& callback) override {
+    return net::OK;
+  }
+};
+
+class HeadlessHttpCache : public net::HttpCache {
+ public:
+  HeadlessHttpCache(net::HttpNetworkSession* session,
+                    HeadlessBrowserContextImpl* headless_browser_context)
+      : net::HttpCache(session,
+                       std::make_unique<HeadlessCacheBackendFactory>(),
+                       true /* is_main_cache */),
+        headless_browser_context_(headless_browser_context) {}
+
+  ~HeadlessHttpCache() override {}
+
+  void WriteMetadata(const GURL& url,
+                     net::RequestPriority priority,
+                     base::Time expected_response_time,
+                     net::IOBuffer* buf,
+                     int buf_len) override {
+    headless_browser_context_->NotifyMetadataForResource(url, buf, buf_len);
+  }
+
+ private:
+  HeadlessBrowserContextImpl* headless_browser_context_;  // NOT OWNED
+};
+
+HeadlessNetworkTransactionFactory::HeadlessNetworkTransactionFactory(
+    net::HttpNetworkSession* session,
+    HeadlessBrowserContextImpl* headless_browser_context)
+    : session_(session),
+      http_cache_(new HeadlessHttpCache(session, headless_browser_context)) {}
+
+HeadlessNetworkTransactionFactory::~HeadlessNetworkTransactionFactory() {}
+
+// static
+std::unique_ptr<net::HttpTransactionFactory>
+HeadlessNetworkTransactionFactory::Create(
+    HeadlessBrowserContextImpl* headless_browser_context,
+    net::HttpNetworkSession* session) {
+  return std::make_unique<HeadlessNetworkTransactionFactory>(
+      session, headless_browser_context);
+}
+
+int HeadlessNetworkTransactionFactory::CreateTransaction(
+    net::RequestPriority priority,
+    std::unique_ptr<net::HttpTransaction>* trans) {
+  return http_cache_->CreateTransaction(priority, trans);
+}
+
+net::HttpCache* HeadlessNetworkTransactionFactory::GetCache() {
+  return http_cache_.get();
+}
+
+net::HttpNetworkSession* HeadlessNetworkTransactionFactory::GetSession() {
+  return session_;
+}
+
+}  // namespace headless
diff --git a/headless/lib/browser/headless_network_transaction_factory.h b/headless/lib/browser/headless_network_transaction_factory.h
new file mode 100644
index 0000000..f2702d7
--- /dev/null
+++ b/headless/lib/browser/headless_network_transaction_factory.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef HEADLESS_LIB_BROWSER_HEADLESS_NETWORK_TRANSACTION_FACTORY_H_
+#define HEADLESS_LIB_BROWSER_HEADLESS_NETWORK_TRANSACTION_FACTORY_H_
+
+#include "base/macros.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_transaction_factory.h"
+
+namespace headless {
+
+class HeadlessBrowserContextImpl;
+
+// This class exists purely to let headless capture resource metadata.
+// In the cases where this used, the headless embedder will have its own
+// protocol handler.
+class HeadlessNetworkTransactionFactory : public net::HttpTransactionFactory {
+ public:
+  HeadlessNetworkTransactionFactory(
+      net::HttpNetworkSession* session,
+      HeadlessBrowserContextImpl* headless_browser_context);
+
+  ~HeadlessNetworkTransactionFactory() override;
+
+  static std::unique_ptr<net::HttpTransactionFactory> Create(
+      HeadlessBrowserContextImpl* headless_browser_context,
+      net::HttpNetworkSession* session);
+
+  // Creates a HttpTransaction object. On success, saves the new
+  // transaction to |*trans| and returns OK.
+  int CreateTransaction(net::RequestPriority priority,
+                        std::unique_ptr<net::HttpTransaction>* trans) override;
+
+  // Returns the associated cache if any (may be NULL).
+  net::HttpCache* GetCache() override;
+
+  // Returns the associated HttpNetworkSession used by new transactions.
+  net::HttpNetworkSession* GetSession() override;
+
+ private:
+  net::HttpNetworkSession* const session_;  // NOT OWNED
+
+  std::unique_ptr<net::HttpCache> http_cache_;
+};
+
+}  // namespace headless
+
+#endif  // HEADLESS_LIB_BROWSER_HEADLESS_NETWORK_TRANSACTION_FACTORY_H_
diff --git a/headless/lib/browser/headless_url_request_context_getter.cc b/headless/lib/browser/headless_url_request_context_getter.cc
index a24ae19b..72d82793 100644
--- a/headless/lib/browser/headless_url_request_context_getter.cc
+++ b/headless/lib/browser/headless_url_request_context_getter.cc
@@ -18,6 +18,7 @@
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_browser_context_options.h"
 #include "headless/lib/browser/headless_network_delegate.h"
+#include "headless/lib/browser/headless_network_transaction_factory.h"
 #include "net/cookies/cookie_store.h"
 #include "net/dns/mapped_host_resolver.h"
 #include "net/http/http_auth_handler_factory.h"
@@ -55,6 +56,7 @@
       proxy_config_(options->proxy_config()),
       request_interceptors_(std::move(request_interceptors)),
       net_log_(net_log),
+      capture_resource_metadata_(options->capture_resource_metadata()),
       headless_browser_context_(headless_browser_context) {
   // Must first be created on the UI thread.
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -225,6 +227,13 @@
       builder.SetCreateHttpTransactionFactoryCallback(
           base::BindOnce(&content::CreateDevToolsNetworkTransactionFactory));
     }
+    if (capture_resource_metadata_) {
+      builder.SetCreateHttpTransactionFactoryCallback(
+          base::BindOnce(&HeadlessNetworkTransactionFactory::Create,
+                         headless_browser_context_));
+      // We want to use the http cache inside HeadlessNetworkTransactionFactory.
+      builder.DisableHttpCache();
+    }
 
     url_request_context_ = builder.Build();
     url_request_context_->set_net_log(net_log_);
diff --git a/headless/lib/browser/headless_url_request_context_getter.h b/headless/lib/browser/headless_url_request_context_getter.h
index e60379e1..80bee7c 100644
--- a/headless/lib/browser/headless_url_request_context_getter.h
+++ b/headless/lib/browser/headless_url_request_context_getter.h
@@ -73,6 +73,7 @@
   content::ProtocolHandlerMap protocol_handlers_;
   content::URLRequestInterceptorScopedVector request_interceptors_;
   net::NetLog* net_log_;  // Not owned
+  bool capture_resource_metadata_;
 
   base::Lock lock_;  // Protects |headless_browser_context_|.
   HeadlessBrowserContextImpl* headless_browser_context_;  // Not owned.
diff --git a/headless/public/headless_browser.cc b/headless/public/headless_browser.cc
index e889d8a..c151221 100644
--- a/headless/public/headless_browser.cc
+++ b/headless/public/headless_browser.cc
@@ -198,6 +198,11 @@
   return *this;
 }
 
+Builder& Builder::SetCaptureResourceMetadata(bool capture_resource_metadata) {
+  options_.capture_resource_metadata = capture_resource_metadata;
+  return *this;
+}
+
 Builder& Builder::SetCrashDumpsDir(const base::FilePath& dir) {
   options_.crash_dumps_dir = dir;
   return *this;
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index ccbedcb..f229662f8 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -194,6 +194,12 @@
   // Whether or not all sites should have a dedicated process.
   bool site_per_process = false;
 
+  // Whether or not the net::HttpCache should be replaced with a custom one that
+  // intercepts metadata writes which are surfaced via
+  // HeadlessBrowserContext::Observer:OnMetadataForResource. The custom cache
+  // blacks holes all writes.
+  bool capture_resource_metadata = false;
+
   // Set a callback that is invoked to override WebPreferences for RenderViews
   // created within the HeadlessBrowser. Called whenever the WebPreferences of a
   // RenderView change. Executed on the browser main thread.
@@ -277,6 +283,7 @@
   Builder& SetOverrideWebPreferencesCallback(
       base::RepeatingCallback<void(WebPreferences*)> callback);
   Builder& SetCrashReporterEnabled(bool enabled);
+  Builder& SetCaptureResourceMetadata(bool capture_resource_metadata);
   Builder& SetCrashDumpsDir(const base::FilePath& dir);
   Builder& SetFontRenderHinting(
       gfx::FontRenderParams::Hinting font_render_hinting);
diff --git a/headless/public/headless_browser_context.h b/headless/public/headless_browser_context.h
index d4d125b8..d401ec4 100644
--- a/headless/public/headless_browser_context.h
+++ b/headless/public/headless_browser_context.h
@@ -25,6 +25,10 @@
 class FilePath;
 }
 
+namespace net {
+class IOBuffer;
+};
+
 namespace headless {
 class HeadlessBrowserImpl;
 class HeadlessBrowserContextOptions;
@@ -96,6 +100,12 @@
                                 int net_error,
                                 DevToolsStatus devtools_status) {}
 
+  // Called when metadata for a resource (e.g. v8 code cache) has been sent by a
+  // renderer.
+  virtual void OnMetadataForResource(const GURL& url,
+                                     net::IOBuffer* buf,
+                                     int buf_len) {}
+
   // Indicates the HeadlessBrowserContext is about to be deleted.
   virtual void OnHeadlessBrowserContextDestruct() {}
 
@@ -144,6 +154,7 @@
   Builder& SetAllowCookies(bool incognito_mode);
   Builder& SetOverrideWebPreferencesCallback(
       base::RepeatingCallback<void(WebPreferences*)> callback);
+  Builder& SetCaptureResourceMetadata(bool capture_resource_metadata);
 
   HeadlessBrowserContext* Build();
 
diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc
index c0dac42c..f13e8f6 100644
--- a/headless/public/util/generic_url_request_job.cc
+++ b/headless/public/util/generic_url_request_job.cc
@@ -136,6 +136,7 @@
     scoped_refptr<net::HttpResponseHeaders> response_headers,
     const char* body,
     size_t body_size,
+    scoped_refptr<net::IOBufferWithSize> metadata,
     const net::LoadTimingInfo& load_timing_info,
     size_t total_received_bytes) {
   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
@@ -144,6 +145,7 @@
   body_size_ = body_size;
   load_timing_info_ = load_timing_info;
   total_received_bytes_ = total_received_bytes;
+  metadata_ = metadata;
 
   // Save any cookies from the response.
   if (!(request_->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES) &&
@@ -195,6 +197,7 @@
 
 void GenericURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
   info->headers = response_headers_;
+  info->metadata = metadata_;
 
   // Important we need to set this so we can detect if a navigation request got
   // canceled by DevTools.
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h
index 25d91ea8..b3ac248 100644
--- a/headless/public/util/generic_url_request_job.h
+++ b/headless/public/util/generic_url_request_job.h
@@ -153,6 +153,7 @@
                        scoped_refptr<net::HttpResponseHeaders> response_headers,
                        const char* body,
                        size_t body_size,
+                       scoped_refptr<net::IOBufferWithSize> metadata,
                        const net::LoadTimingInfo& load_timing_info,
                        size_t total_received_bytes) override;
 
@@ -189,6 +190,7 @@
   HeadlessBrowserContext* headless_browser_context_;           // Not owned.
   const content::ResourceRequestInfo* request_resource_info_;  // Not owned.
   const char* body_ = nullptr;  // Not owned.
+  scoped_refptr<net::IOBufferWithSize> metadata_;
   size_t body_size_ = 0;
   size_t read_offset_ = 0;
   net::LoadTimingInfo load_timing_info_;
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc
index 629fc36..fdfe1cd 100644
--- a/headless/public/util/generic_url_request_job_test.cc
+++ b/headless/public/util/generic_url_request_job_test.cc
@@ -133,7 +133,8 @@
       total_received_bytes = total_received_bytes_value->GetInt();
     result_listener->OnFetchComplete(
         GURL(final_url_value->GetString()), std::move(response_headers),
-        response_data_.c_str(), response_data_.size(), load_timing_info,
+        response_data_.c_str(), response_data_.size(),
+        scoped_refptr<net::IOBufferWithSize>(), load_timing_info,
         total_received_bytes);
   }
 
diff --git a/headless/public/util/http_url_fetcher.cc b/headless/public/util/http_url_fetcher.cc
index b53dee9e..85698d4 100644
--- a/headless/public/util/http_url_fetcher.cc
+++ b/headless/public/util/http_url_fetcher.cc
@@ -224,8 +224,8 @@
   // TODO(jzfeng) fill in the real total received bytes from network.
   result_listener_->OnFetchComplete(
       request->url(), request->response_info().headers,
-      bytes_read_so_far_.c_str(), bytes_read_so_far_.size(), load_timing_info,
-      0);
+      bytes_read_so_far_.c_str(), bytes_read_so_far_.size(),
+      scoped_refptr<net::IOBufferWithSize>(), load_timing_info, 0);
 }
 
 HttpURLFetcher::HttpURLFetcher(
diff --git a/headless/public/util/testing/test_in_memory_protocol_handler.cc b/headless/public/util/testing/test_in_memory_protocol_handler.cc
index f2dbb18..bdc718a8 100644
--- a/headless/public/util/testing/test_in_memory_protocol_handler.cc
+++ b/headless/public/util/testing/test_in_memory_protocol_handler.cc
@@ -54,8 +54,8 @@
       net::LoadTimingInfo load_timing_info;
       load_timing_info.receive_headers_end = base::TimeTicks::Now();
       result_listener->OnFetchCompleteExtractHeaders(
-          url, response->data.c_str(), response->data.size(), load_timing_info,
-          0);
+          url, response->data.c_str(), response->data.size(),
+          response->metadata, load_timing_info, 0);
     } else {
       result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND);
     }
@@ -108,16 +108,21 @@
 
 void TestInMemoryProtocolHandler::InsertResponse(const std::string& url,
                                                  const Response& response) {
-  response_map_[url] = response;
+  response_map_[url].reset(new Response(response));
+}
+
+void TestInMemoryProtocolHandler::SetResponseMetadata(
+    const std::string& url,
+    scoped_refptr<net::IOBufferWithSize> metadata) {
+  response_map_[url]->metadata = metadata;
 }
 
 const TestInMemoryProtocolHandler::Response*
 TestInMemoryProtocolHandler::GetResponse(const std::string& url) const {
-  std::map<std::string, Response>::const_iterator find_it =
-      response_map_.find(url);
+  const auto find_it = response_map_.find(url);
   if (find_it == response_map_.end())
     return nullptr;
-  return &find_it->second;
+  return find_it->second.get();
 }
 
 net::URLRequestJob* TestInMemoryProtocolHandler::MaybeCreateJob(
diff --git a/headless/public/util/testing/test_in_memory_protocol_handler.h b/headless/public/util/testing/test_in_memory_protocol_handler.h
index 92a7fa2..aa7cf60 100644
--- a/headless/public/util/testing/test_in_memory_protocol_handler.h
+++ b/headless/public/util/testing/test_in_memory_protocol_handler.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
+#include "net/base/io_buffer.h"
 #include "net/url_request/url_request_job_factory.h"
 
 namespace headless {
@@ -48,9 +49,12 @@
                body) {}
 
     std::string data;
+    scoped_refptr<net::IOBufferWithSize> metadata;
   };
 
   void InsertResponse(const std::string& url, const Response& response);
+  void SetResponseMetadata(const std::string& url,
+                           scoped_refptr<net::IOBufferWithSize> metadata);
 
   // net::URLRequestJobFactory::ProtocolHandler implementation::
   net::URLRequestJob* MaybeCreateJob(
@@ -86,7 +90,7 @@
 
   std::unique_ptr<TestDelegate> test_delegate_;
   std::unique_ptr<ExpeditedDispatcher> dispatcher_;
-  std::map<std::string, Response> response_map_;
+  std::map<std::string, std::unique_ptr<Response>> response_map_;
   HeadlessBrowserContext* headless_browser_context_;
   std::map<std::string, std::string> url_to_devtools_frame_id_;
   std::vector<std::string> urls_requested_;
diff --git a/headless/public/util/url_fetcher.cc b/headless/public/util/url_fetcher.cc
index 9a7bfe81..80dd968c 100644
--- a/headless/public/util/url_fetcher.cc
+++ b/headless/public/util/url_fetcher.cc
@@ -16,6 +16,7 @@
     const GURL& final_url,
     const char* response_data,
     size_t response_data_size,
+    scoped_refptr<net::IOBufferWithSize> metadata,
     const net::LoadTimingInfo& load_timing_info,
     size_t total_received_bytes) {
   size_t read_offset = 0;
@@ -35,7 +36,7 @@
   CHECK_LE(read_offset, response_data_size);
   OnFetchComplete(final_url, std::move(response_headers),
                   response_data + read_offset, response_data_size - read_offset,
-                  load_timing_info, total_received_bytes);
+                  std::move(metadata), load_timing_info, total_received_bytes);
 }
 
 }  // namespace headless
diff --git a/headless/public/util/url_fetcher.h b/headless/public/util/url_fetcher.h
index e7955680..bd2d3985 100644
--- a/headless/public/util/url_fetcher.h
+++ b/headless/public/util/url_fetcher.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "headless/public/headless_export.h"
+#include "net/base/io_buffer.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/net_errors.h"
 #include "url/gurl.h"
@@ -45,6 +46,7 @@
         scoped_refptr<net::HttpResponseHeaders> response_headers,
         const char* body,
         size_t body_size,
+        scoped_refptr<net::IOBufferWithSize> metadata,
         const net::LoadTimingInfo& load_timing_info,
         size_t total_received_bytes) = 0;
 
@@ -54,6 +56,7 @@
         const GURL& final_url,
         const char* response_data,
         size_t response_data_size,
+        scoped_refptr<net::IOBufferWithSize> metadata,
         const net::LoadTimingInfo& load_timing_info,
         size_t total_received_bytes);
 
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc
index c2122ac..ca101397 100644
--- a/headless/test/headless_browser_test.cc
+++ b/headless/test/headless_browser_test.cc
@@ -252,10 +252,13 @@
   browser()->SetDefaultBrowserContext(browser_context_);
   browser()->GetDevToolsTarget()->AttachClient(browser_devtools_client_.get());
 
-  web_contents_ = browser_context_->CreateWebContentsBuilder()
-                      .SetAllowTabSockets(GetAllowTabSockets())
-                      .SetEnableBeginFrameControl(GetEnableBeginFrameControl())
-                      .Build();
+  HeadlessWebContents::Builder web_contents_builder =
+      browser_context_->CreateWebContentsBuilder();
+  web_contents_builder.SetAllowTabSockets(GetAllowTabSockets());
+  web_contents_builder.SetEnableBeginFrameControl(GetEnableBeginFrameControl());
+  CustomizeHeadlessWebContents(web_contents_builder);
+  web_contents_ = web_contents_builder.Build();
+
   web_contents_->AddObserver(this);
 
   RunAsynchronousTest();
@@ -285,4 +288,7 @@
 void HeadlessAsyncDevTooledBrowserTest::CustomizeHeadlessBrowserContext(
     HeadlessBrowserContext::Builder& builder) {}
 
+void HeadlessAsyncDevTooledBrowserTest::CustomizeHeadlessWebContents(
+    HeadlessWebContents::Builder& builder) {}
+
 }  // namespace headless
diff --git a/headless/test/headless_browser_test.h b/headless/test/headless_browser_test.h
index 8582a79..349d62b 100644
--- a/headless/test/headless_browser_test.h
+++ b/headless/test/headless_browser_test.h
@@ -151,6 +151,10 @@
   virtual void CustomizeHeadlessBrowserContext(
       HeadlessBrowserContext::Builder& builder);
 
+  // Allows the HeadlessWebContents used in testing to be customized.
+  virtual void CustomizeHeadlessWebContents(
+      HeadlessWebContents::Builder& builder);
+
  protected:
   void RunTest();
 
diff --git a/headless/test/headless_js_bindings_browsertest.cc b/headless/test/headless_js_bindings_browsertest.cc
index f3042d6..cafa8830 100644
--- a/headless/test/headless_js_bindings_browsertest.cc
+++ b/headless/test/headless_js_bindings_browsertest.cc
@@ -15,11 +15,13 @@
 #include "content/public/common/isolated_world_ids.h"
 #include "content/public/test/browser_test.h"
 #include "headless/grit/headless_browsertest_resources.h"
+#include "headless/public/devtools/domains/page.h"
 #include "headless/public/devtools/domains/runtime.h"
 #include "headless/public/headless_browser.h"
 #include "headless/public/headless_devtools_client.h"
 #include "headless/public/headless_tab_socket.h"
 #include "headless/public/headless_web_contents.h"
+#include "headless/public/util/testing/test_in_memory_protocol_handler.h"
 #include "headless/test/tab_socket_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -27,10 +29,28 @@
 
 namespace headless {
 
+namespace {
+static constexpr char kIndexHtml[] = R"(
+<html>
+<body>
+<script src="bindings.js"></script>
+</body>
+</html>
+)";
+}  // namespace
+
 class HeadlessJsBindingsTest
-    : public TabSocketTest,
-      public HeadlessDevToolsClient::RawProtocolListener {
+    : public HeadlessAsyncDevTooledBrowserTest,
+      public HeadlessDevToolsClient::RawProtocolListener,
+      public TestInMemoryProtocolHandler::RequestDeferrer,
+      public HeadlessTabSocket::Listener,
+      public page::ExperimentalObserver {
  public:
+  void SetUp() override {
+    options()->mojo_service_names.insert("headless::TabSocket");
+    HeadlessAsyncDevTooledBrowserTest::SetUp();
+  }
+
   void SetUpOnMainThread() override {
     base::ThreadRestrictions::SetIOAllowed(true);
     base::FilePath pak_path;
@@ -40,36 +60,91 @@
         pak_path, ui::SCALE_FACTOR_NONE);
   }
 
-  void RunTabSocketTest() override {
+  void CustomizeHeadlessBrowserContext(
+      HeadlessBrowserContext::Builder& builder) override {
+    builder.AddTabSocketMojoBindings();
+    builder.EnableUnsafeNetworkAccessWithMojoBindings(true);
+  }
+
+  void CustomizeHeadlessWebContents(
+      HeadlessWebContents::Builder& builder) override {
+    builder.SetWindowSize(gfx::Size(0, 0));
+    builder.SetInitialURL(GURL("http://test.com/index.html"));
+
+    http_handler_->SetHeadlessBrowserContext(browser_context_);
+  }
+
+  bool GetAllowTabSockets() override { return true; }
+
+  ProtocolHandlerMap GetProtocolHandlers() override {
+    ProtocolHandlerMap protocol_handlers;
+    std::unique_ptr<TestInMemoryProtocolHandler> http_handler(
+        new TestInMemoryProtocolHandler(browser()->BrowserIOThread(), this));
+    http_handler_ = http_handler.get();
+    bindings_js_ = ui::ResourceBundle::GetSharedInstance()
+                       .GetRawDataResource(DEVTOOLS_BINDINGS_TEST)
+                       .as_string();
+    http_handler->InsertResponse("http://test.com/index.html",
+                                 {kIndexHtml, "text/html"});
+    http_handler->InsertResponse(
+        "http://test.com/bindings.js",
+        {bindings_js_.c_str(), "application/javascript"});
+    protocol_handlers[url::kHttpScheme] = std::move(http_handler);
+    return protocol_handlers;
+  }
+
+  void RunDevTooledTest() override {
+    devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
+    devtools_client_->GetPage()->Enable();
     headless_tab_socket_ = web_contents_->GetHeadlessTabSocket();
     CHECK(headless_tab_socket_);
     headless_tab_socket_->SetListener(this);
     devtools_client_->SetRawProtocolListener(this);
-    CreateMainWorldTabSocket(
-        main_frame_id(),
+
+    headless_tab_socket_->InstallMainFrameMainWorldHeadlessTabSocketBindings(
         base::BindOnce(&HeadlessJsBindingsTest::OnInstalledHeadlessTabSocket,
                        base::Unretained(this)));
   }
 
-  void OnInstalledHeadlessTabSocket(int v8_exection_context_id) {
-    main_world_execution_context_id_ = v8_exection_context_id;
-    devtools_client_->GetRuntime()->Evaluate(
-        ui::ResourceBundle::GetSharedInstance()
-            .GetRawDataResource(DEVTOOLS_BINDINGS_TEST)
-            .as_string(),
-        base::BindOnce(&HeadlessJsBindingsTest::OnEvaluateResult,
-                       base::Unretained(this)));
+  void OnRequest(const GURL& url,
+                 base::RepeatingClosure complete_request) override {
+    if (!tab_socket_installed_ && url.spec() == "http://test.com/bindings.js") {
+      complete_request_ = std::move(complete_request);
+    } else {
+      complete_request.Run();
+    }
+  }
+
+  void OnInstalledHeadlessTabSocket(base::Optional<int> context_id) {
+    main_world_execution_context_id_ = *context_id;
+    tab_socket_installed_ = true;
+    if (complete_request_) {
+      browser()->BrowserIOThread()->PostTask(FROM_HERE, complete_request_);
+      complete_request_ = base::RepeatingClosure();
+    }
   }
 
   virtual void RunJsBindingsTest() = 0;
-  virtual std::string GetExpectedResult() = 0;
 
-  void OnEvaluateResult(std::unique_ptr<runtime::EvaluateResult> result) {
-    if (!result->HasExceptionDetails()) {
-      RunJsBindingsTest();
-    } else {
-      FailOnJsEvaluateException(std::move(result));
-    }
+  void OnLoadEventFired(const page::LoadEventFiredParams& params) override {
+    RunJsBindingsTest();
+  }
+
+  virtual void OnResult(const std::string& result) = 0;
+
+  void FailOnJsEvaluateException(
+      std::unique_ptr<runtime::EvaluateResult> result) {
+    if (!result->HasExceptionDetails())
+      return;
+
+    FinishAsynchronousTest();
+
+    const runtime::ExceptionDetails* exception_details =
+        result->GetExceptionDetails();
+    FAIL() << exception_details->GetText()
+           << (exception_details->HasException()
+                   ? exception_details->GetException()->GetDescription().c_str()
+                   : "");
   }
 
   void OnMessageFromContext(const std::string& json_message,
@@ -99,9 +174,7 @@
     }
 
     if (method_value->GetString() == "__Result") {
-      EXPECT_EQ(GetExpectedResult(),
-                params_value->FindKey("result")->GetString());
-      FinishAsynchronousTest();
+      OnResult(params_value->FindKey("result")->GetString());
       return;
     }
 
@@ -111,6 +184,9 @@
   bool OnProtocolMessage(const std::string& devtools_agent_host_id,
                          const std::string& json_message,
                          const base::DictionaryValue& parsed_message) override {
+    if (main_world_execution_context_id_ == -1)
+      return false;
+
     const base::Value* id_value = parsed_message.FindKey("id");
     // If |parsed_message| contains an id we know this is a message reply.
     if (id_value) {
@@ -142,9 +218,13 @@
     return sections[0] == "DOM" || sections[0] == "Runtime";
   }
 
- private:
-  HeadlessTabSocket* headless_tab_socket_;
-  int main_world_execution_context_id_;
+ protected:
+  TestInMemoryProtocolHandler* http_handler_;  // NOT OWNED
+  HeadlessTabSocket* headless_tab_socket_;     // NOT OWNED
+  int main_world_execution_context_id_ = -1;
+  std::string bindings_js_;
+  base::RepeatingClosure complete_request_;
+  bool tab_socket_installed_ = false;
 };
 
 class SimpleCommandJsBindingsTest : public HeadlessJsBindingsTest {
@@ -156,7 +236,10 @@
                        base::Unretained(this)));
   }
 
-  std::string GetExpectedResult() override { return "2"; }
+  void OnResult(const std::string& result) override {
+    EXPECT_EQ("2", result);
+    FinishAsynchronousTest();
+  }
 };
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(SimpleCommandJsBindingsTest);
@@ -170,8 +253,9 @@
                        base::Unretained(this)));
   }
 
-  std::string GetExpectedResult() override {
-    return "Created Test Isolated World";
+  void OnResult(const std::string& result) override {
+    EXPECT_EQ("Created Test Isolated World", result);
+    FinishAsynchronousTest();
   }
 };
 
@@ -186,11 +270,97 @@
                        base::Unretained(this)));
   }
 
-  std::string GetExpectedResult() override {
-    return "{\"nodeId\":4,\"childNodeCount\":1}";
+  void OnResult(const std::string& result) override {
+    EXPECT_EQ("{\"nodeId\":4,\"childNodeCount\":2}", result);
+    FinishAsynchronousTest();
   }
 };
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(SimpleEventJsBindingsTest);
 
+/*
+ * Like SimpleCommandJsBindingsTest except it's run twice. On the first run
+ * metadata is produced by v8 for http://test.com/bindings.js. On the second run
+ * the metadata is used used leading to substantially faster execution time.
+ */
+class CachedJsBindingsTest : public HeadlessJsBindingsTest,
+                             public HeadlessBrowserContext::Observer {
+ public:
+  void CustomizeHeadlessBrowserContext(
+      HeadlessBrowserContext::Builder& builder) override {
+    builder.SetCaptureResourceMetadata(true);
+    builder.SetOverrideWebPreferencesCallback(base::BindRepeating(
+        &CachedJsBindingsTest::OverrideWebPreferences, base::Unretained(this)));
+    HeadlessJsBindingsTest::CustomizeHeadlessBrowserContext(builder);
+  }
+
+  void OverrideWebPreferences(WebPreferences* preferences) {
+    // Request eager code compilation.
+    preferences->v8_cache_options =
+        content::V8_CACHE_OPTIONS_FULLCODE_WITHOUT_HEAT_CHECK;
+  }
+
+  void RunDevTooledTest() override {
+    browser_context_->AddObserver(this);
+    HeadlessJsBindingsTest::RunDevTooledTest();
+  }
+
+  void RunJsBindingsTest() override {
+    devtools_client_->GetRuntime()->Evaluate(
+        "new chromium.BindingsTest().evalOneAddOne();",
+        base::BindRepeating(&HeadlessJsBindingsTest::FailOnJsEvaluateException,
+                            base::Unretained(this)));
+  }
+
+  void OnResult(const std::string& result) override {
+    EXPECT_EQ("2", result);
+
+    if (first_result) {
+      tab_socket_installed_ = false;
+      main_world_execution_context_id_ = -1;
+      devtools_client_->GetPage()->Reload();
+    } else {
+      EXPECT_TRUE(metadata_received_);
+      FinishAsynchronousTest();
+    }
+    first_result = false;
+  }
+
+  // Called on the IO thread.
+  void OnRequest(const GURL& url,
+                 base::RepeatingClosure complete_request) override {
+    HeadlessJsBindingsTest::OnRequest(url, complete_request);
+    if (!first_result && url.spec() == "http://test.com/bindings.js") {
+      browser()->BrowserMainThread()->PostTask(
+          FROM_HERE,
+          base::BindOnce(&CachedJsBindingsTest::ReinstallTabSocketBindings,
+                         base::Unretained(this)));
+    }
+  }
+
+  void ReinstallTabSocketBindings() {
+    headless_tab_socket_->InstallMainFrameMainWorldHeadlessTabSocketBindings(
+        base::BindRepeating(
+            &HeadlessJsBindingsTest::OnInstalledHeadlessTabSocket,
+            base::Unretained(this)));
+  }
+
+  void OnMetadataForResource(const GURL& url,
+                             net::IOBuffer* buf,
+                             int buf_len) override {
+    ASSERT_FALSE(metadata_received_);
+    metadata_received_ = true;
+
+    scoped_refptr<net::IOBufferWithSize> metadata(
+        new net::IOBufferWithSize(buf_len));
+    memcpy(metadata->data(), buf->data(), buf_len);
+    http_handler_->SetResponseMetadata(url.spec(), metadata);
+  }
+
+  bool metadata_received_ = false;
+  bool first_result = true;
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(CachedJsBindingsTest);
+
 }  // namespace headless
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index 3333456..13dd5dc 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -153,6 +153,22 @@
         name: "mac_chromium_rel_ng"
         equivalent_to { bucket: "luci.chromium.try" percentage: 0 }
       }
+      builders {
+        # The only purpose of this builder here is get data for migrating this
+        # builder to LUCI, see https://crbug.com/731360.
+        # TODO(tandrii): remove this builder once enough data has been
+        # collected.
+        name: "mac_chromium_10.12_rel_ng"
+        experiment_percentage: 5
+      }
+      builders {
+        # The only purpose of this builder here is get data for migrating this
+        # builder to LUCI, see https://crbug.com/807149.
+        # TODO(tandrii): remove this builder once enough data has been
+        # collected.
+        name: "mac_chromium_10.13_rel_ng"
+        experiment_percentage: 5
+      }
     }
     buckets {
       name: "master.tryserver.chromium.win"
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 07fa355..c083bf9 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -591,6 +591,32 @@
 
     # Mac bots.
     builders {
+      name: "Mac Builder"
+      mixins: "mac-ci"
+    }
+    builders {
+      name: "Mac10.10 Tests"
+      mixins: "mac-ci"
+      dimensions:"os:Mac-10.10"
+    }
+    builders {
+      name: "Mac10.11 Tests"
+      mixins: "mac-ci"
+      dimensions:"os:Mac-10.11"
+    }
+    builders {
+      name: "Mac10.12 Tests"
+      mixins: "mac-ci"
+      # TODO(tandrii: change to default (8 cores) per crbug/826308.
+      dimensions: "cores:4"
+      dimensions:"os:Mac-10.12"
+    }
+    builders {
+      name: "Mac10.13 Tests"
+      mixins: "mac-ci"
+      dimensions:"os:Mac-10.13"
+    }
+    builders {
       name: "Mac Builder (dbg)"
       mixins: "mac-ci"
     }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 3ededbc..83ce6ec3 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -340,30 +340,35 @@
 
   builders: {
     name: "buildbot/chromium.mac/Mac Builder"
+    name: "buildbucket/luci.chromium.ci/Mac Builder"
     category: "chromium.mac|release"
     short_name: "bld"
   }
   builders: {
-    name: "buildbot/chromium.mac/Mac10.13 Tests"
-    category: "chromium.mac|release|tester"
-    short_name: "13"
-  }
-  builders: {
     name: "buildbot/chromium.mac/Mac10.10 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.10 Tests"
     category: "chromium.mac|release|tester"
     short_name: "10"
   }
   builders: {
     name: "buildbot/chromium.mac/Mac10.11 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.11 Tests"
     category: "chromium.mac|release|tester"
     short_name: "11"
   }
   builders: {
     name: "buildbot/chromium.mac/Mac10.12 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.12 Tests"
     category: "chromium.mac|release|tester"
     short_name: "12"
   }
   builders: {
+    name: "buildbot/chromium.mac/Mac10.13 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.13 Tests"
+    category: "chromium.mac|release|tester"
+    short_name: "13"
+  }
+  builders: {
     name: "buildbot/chromium.mac/Mac Builder (dbg)"
     name: "buildbucket/luci.chromium.ci/Mac Builder (dbg)"
     category: "chromium.mac|debug"
@@ -804,30 +809,35 @@
 
   builders: {
     name: "buildbot/chromium.mac/Mac Builder"
+    name: "buildbucket/luci.chromium.ci/Mac Builder"
     category: "release"
     short_name: "bld"
   }
   builders: {
-    name: "buildbot/chromium.mac/Mac10.13 Tests"
-    category: "release|tester"
-    short_name: "13"
-  }
-  builders: {
     name: "buildbot/chromium.mac/Mac10.10 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.10 Tests"
     category: "release|tester"
     short_name: "10"
   }
   builders: {
     name: "buildbot/chromium.mac/Mac10.11 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.11 Tests"
     category: "release|tester"
     short_name: "11"
   }
   builders: {
     name: "buildbot/chromium.mac/Mac10.12 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.12 Tests"
     category: "release|tester"
     short_name: "12"
   }
   builders: {
+    name: "buildbot/chromium.mac/Mac10.13 Tests"
+    name: "buildbucket/luci.chromium.ci/Mac10.13 Tests"
+    category: "release|tester"
+    short_name: "13"
+  }
+  builders: {
     name: "buildbot/chromium.mac/Mac Builder (dbg)"
     name: "buildbucket/luci.chromium.ci/Mac Builder (dbg)"
     category: "debug"
@@ -1872,6 +1882,64 @@
 
 }
 
+consoles: {
+  # Additional migration console because the above has too many columns
+  # (builders) as of March 26, 2018.
+  # TODO(tandrii): remove this once https://crbug.com/790157 is complete.
+  id: "migration-side-by-side-of-macs"
+  name: "LUCI CI Mac Migration Comparison Console"
+  repo_url: "https://chromium.googlesource.com/chromium/src"
+  ref: "refs/heads/master"
+  manifest_name: "REVISION"
+  header_id: "chromium"
+  include_experimental_builds: true
+
+  builders: {
+    name: "buildbot/chromium.mac/Mac Builder"
+    short_name: "old"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac Builder"
+    short_name: "new"
+  }
+
+  builders: {
+    name: "buildbot/chromium.mac/Mac10.10 Tests"
+    short_name: "old"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac10.10 Tests"
+    short_name: "new"
+  }
+
+  builders: {
+    name: "buildbot/chromium.mac/Mac10.11 Tests"
+    short_name: "old"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac10.11 Tests"
+    short_name: "new"
+  }
+
+  builders: {
+    name: "buildbot/chromium.mac/Mac10.12 Tests"
+    short_name: "old"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac10.12 Tests"
+    short_name: "new"
+  }
+
+  builders: {
+    name: "buildbot/chromium.mac/Mac10.13 Tests"
+    short_name: "old"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac10.13 Tests"
+    short_name: "new"
+  }
+}
+
 # Everything below was generated from buildermap.json.
 consoles: {
   id: "chromium"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 9779a19..1a3be2e 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -90,6 +90,7 @@
   triggers: "GPU FYI Mac Builder"
   triggers: "GPU FYI Mac Builder (dbg)"
   triggers: "GPU FYI Mac dEQP Builder"
+  triggers: "Mac Builder"
   triggers: "Mac Builder (dbg)"
   triggers: "Mac FYI GPU ASAN Release"
   triggers: "WebKit Mac Builder (dbg)"
@@ -829,6 +830,16 @@
 }
 
 job {
+  id: "Mac Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac Builder"
+  }
+}
+
+job {
   id: "Mac Builder (dbg)"
   acl_sets: "default"
   buildbucket: {
@@ -849,6 +860,50 @@
 }
 
 job {
+  id: "Mac10.10 Tests"
+  # Triggered by "Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac10.10 Tests"
+  }
+}
+
+job {
+  id: "Mac10.11 Tests"
+  # Triggered by "Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac10.11 Tests"
+  }
+}
+
+job {
+  id: "Mac10.12 Tests"
+  # Triggered by "Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac10.12 Tests"
+  }
+}
+
+job {
+  id: "Mac10.13 Tests"
+  # Triggered by "Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac10.13 Tests"
+  }
+}
+
+job {
   id: "Mac10.13 Tests (dbg)"
   # Triggered by "Mac Builder (dbg)".
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
index dbc2f2b5..f480771 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
@@ -23,43 +23,106 @@
       "include": "eg_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "10.0",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "10.0",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "11.2",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPad Air 2",
       "os": "10.0",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "11.2",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     }
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-simulator.json b/ios/build/bots/chromium.mac/ios-simulator.json
index 4f317fe..044fea8 100644
--- a/ios/build/bots/chromium.mac/ios-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-simulator.json
@@ -24,43 +24,106 @@
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "11.2",
-      "host os": "Mac-10.12"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "10.0",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
       "os": "10.0",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "11.2",
-      "host os": "Mac-10.13"
+      "dimensions": [
+        {
+          "os": "Mac-10.12",
+          "pool": "Chrome"
+        },
+        {
+          "os": "Mac-10.13",
+          "pool": "Chrome"
+        }
+      ]
     }
   ]
 }
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 4568677..5555448 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -139,6 +139,7 @@
     "//components/keyed_service/ios",
     "//components/metrics",
     "//components/ntp_snippets",
+    "//components/password_manager/core/common",
     "//components/payments/core",
     "//components/prefs",
     "//components/proxy_config",
@@ -175,6 +176,7 @@
     "//ios/chrome/browser/net",
     "//ios/chrome/browser/ntp_snippets",
     "//ios/chrome/browser/omaha",
+    "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/payments",
     "//ios/chrome/browser/payments:constants",
     "//ios/chrome/browser/prefs",
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS
index 19695943..1cd9d1be 100644
--- a/ios/chrome/app/DEPS
+++ b/ios/chrome/app/DEPS
@@ -13,6 +13,7 @@
   "+components/history/core/browser",
   "+components/metrics",
   "+components/ntp_snippets",
+  "+components/password_manager/core/common",
   "+components/payments/core",
   "+components/prefs",
   "+components/reading_list/core",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 961d252f..8785a39f 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -33,6 +33,7 @@
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/payments/core/features.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -86,6 +87,7 @@
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 #import "ios/chrome/browser/net/cookie_util.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
+#import "ios/chrome/browser/passwords/passwords_directory_util.h"
 #include "ios/chrome/browser/payments/ios_payment_instrument_launcher.h"
 #include "ios/chrome/browser/payments/ios_payment_instrument_launcher_factory.h"
 #import "ios/chrome/browser/payments/payment_request_constants.h"
@@ -197,6 +199,9 @@
 // Constants for deferred deletion of leftover user downloaded files.
 NSString* const kDeleteDownloads = @"DeleteDownloads";
 
+// Constants for deferred deletion of leftover temporary passwords files.
+NSString* const kDeleteTempPasswords = @"DeleteTempPasswords";
+
 // Constants for deferred sending of queued feedback.
 NSString* const kSendQueuedFeedback = @"SendQueuedFeedback";
 
@@ -502,6 +507,9 @@
 // Schedules the deletion of user downloaded files that might be leftover
 // from the last time Chrome was run.
 - (void)scheduleDeleteDownloadsDirectory;
+// Schedule the deletion of the temporary passwords files that might
+// be left over from incomplete export operations.
+- (void)scheduleDeleteTempPasswordsDirectory;
 // Returns whether or not the app can launch in incognito mode.
 - (BOOL)canLaunchInIncognito;
 // Determines which UI should be shown on startup, and shows it.
@@ -1150,6 +1158,10 @@
   [self sendQueuedFeedback];
   [self scheduleSpotlightResync];
   [self scheduleDeleteDownloadsDirectory];
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordExport)) {
+    [self scheduleDeleteTempPasswordsDirectory];
+  }
   [self scheduleStartupAttemptReset];
   [self startFreeMemoryMonitoring];
   [self scheduleAppDistributionPings];
@@ -1177,6 +1189,14 @@
                   }];
 }
 
+- (void)scheduleDeleteTempPasswordsDirectory {
+  [[DeferredInitializationRunner sharedInstance]
+      enqueueBlockNamed:kDeleteTempPasswords
+                  block:^{
+                    DeletePasswordsDirectory();
+                  }];
+}
+
 - (void)scheduleSpotlightResync {
   if (!_spotlightManager) {
     return;
diff --git a/ios/chrome/app/strings/resources/ios_strings_ru.xtb b/ios/chrome/app/strings/resources/ios_strings_ru.xtb
index 9758a023..4defc7c 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ru.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ru.xtb
@@ -38,6 +38,7 @@
 <translation id="1540800554400757039">Адрес, строка 1</translation>
 <translation id="1545749641540134597">Сканирование QR-кода</translation>
 <translation id="1580783302095112590">Сообщение отправлено.</translation>
+<translation id="1582732959743469162">Скачивание файлов будет приостановлено.</translation>
 <translation id="1612730193129642006">Показать сетку таблицы</translation>
 <translation id="1644574205037202324">История</translation>
 <translation id="1646446875146297738">Если запретить отслеживание, в запросы браузера будет включена специальная команда. Результат этого действия будет зависеть от того, ответит ли сайт на запрос и каким образом он будет интерпретирован.
@@ -284,6 +285,7 @@
 <translation id="633809752005859102">Произошла ошибка. Мы постараемся ее устранить.</translation>
 <translation id="6342069812937806050">только что</translation>
 <translation id="6344783595350022745">Очистить</translation>
+<translation id="6346549652287021269">Скачать новый файл?</translation>
 <translation id="6362362396625799311">Нет открытых вкладок инкогнито</translation>
 <translation id="6374469231428023295">Повторить</translation>
 <translation id="6380866119319257197">Если вы забыли кодовую фразу или хотите изменить эту настройку, <ph name="BEGIN_LINK" />сбросьте параметры синхронизации<ph name="END_LINK" />.</translation>
@@ -325,6 +327,7 @@
 <translation id="7031882061095297553">Выберите аккаунт</translation>
 <translation id="7053983685419859001">Блокировать</translation>
 <translation id="7062545763355031412">Принять и переключиться</translation>
+<translation id="7102005569666697658">Скачивание… <ph name="FILE_SIZE" /></translation>
 <translation id="7108338896283013870">Скрыть</translation>
 <translation id="7133798577887235672">Полное имя</translation>
 <translation id="7136892417564438900">Камера недоступна</translation>
@@ -360,6 +363,7 @@
 <translation id="7769602470925380267">Принять и выйти</translation>
 <translation id="7772032839648071052">Подтвердите кодовую фразу</translation>
 <translation id="780301667611848630">Спасибо, не надо</translation>
+<translation id="7856733331829174190">Не удалось скачать файл</translation>
 <translation id="7859704718976024901">История просмотра веб-страниц</translation>
 <translation id="7938254975914653459">FaceTime</translation>
 <translation id="7939128259257418052">Экспорт паролей...</translation>
@@ -422,6 +426,7 @@
 <translation id="9083392325882095631">Закладок: 1</translation>
 <translation id="9100610230175265781">Необходима кодовая фраза</translation>
 <translation id="9148126808321036104">Повторите вход</translation>
+<translation id="915371508759614899">Отменить скачивание?</translation>
 <translation id="9157836665414082580">Блокировать диалоговые окна</translation>
 <translation id="9188680907066685419">Выход из управляемого аккаунта</translation>
 <translation id="9203116392574189331">Handoff</translation>
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index bf700ac..a8ce923 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -131,6 +131,14 @@
     {"Top navigation", kToolbarButtonPositionsSwitch, "2"},
 };
 
+const FeatureEntry::Choice kSearchButtonIconChoices[] = {
+    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {"Grey search engine logo", kIconSearchButtonSwitch, kIconSearchButtonGrey},
+    {"Colorful search engine logo", kIconSearchButtonSwitch,
+     kIconSearchButtonColorful},
+    {"Magnifying glass", kIconSearchButtonSwitch, kIconSearchButtonMagnifying},
+};
+
 // To add a new entry, add to the end of kFeatureEntries. There are four
 // distinct types of entries:
 // . ENABLE_DISABLE_VALUE: entry is either enabled, disabled, or uses the
@@ -257,6 +265,9 @@
     {"toolbar-button-positions", flag_descriptions::kToolbarButtonPositionsName,
      flag_descriptions::kToolbarButtonPositionsDescription, flags_ui::kOsIos,
      MULTI_VALUE_TYPE(kToolbarButtonPositionsChoices)},
+    {"search-icon-toggle", flag_descriptions::kSearchIconToggleName,
+     flag_descriptions::kSearchIconToggleDescription, flags_ui::kOsIos,
+     MULTI_VALUE_TYPE(kSearchButtonIconChoices)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
index 72ddbc02..d781ff8 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
@@ -354,9 +354,9 @@
   network_delegate->set_cookie_settings(profile_params_->cookie_settings.get());
   network_delegate->set_enable_do_not_track(&enable_do_not_track_);
 
-  // NOTE: Proxy service uses the default io thread network delegate, not the
-  // delegate just created.
-  proxy_resolution_service_ = ProxyServiceFactory::CreateProxyService(
+  // NOTE: The proxy resolution service uses the default io thread network
+  // delegate, not the delegate just created.
+  proxy_resolution_service_ = ProxyServiceFactory::CreateProxyResolutionService(
       io_thread->net_log(), nullptr,
       io_thread_globals->system_network_delegate.get(),
       std::move(profile_params_->proxy_config_service),
diff --git a/ios/chrome/browser/download/download_manager_metric_names.h b/ios/chrome/browser/download/download_manager_metric_names.h
index 03b9cf9..f27371e 100644
--- a/ios/chrome/browser/download/download_manager_metric_names.h
+++ b/ios/chrome/browser/download/download_manager_metric_names.h
@@ -34,6 +34,8 @@
   // In progress download did no finish because the tab was closed or user has
   // quit the app.
   Other = 3,
+  // The user closed Download Manager UI without starting the download.
+  NotStarted = 4,
   Count
 };
 
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index e37abb216..ab98f3a 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -134,6 +134,10 @@
 const char kUIRefreshPhase1Description[] =
     "When enabled, the first phase of the iOS UI refresh will be displayed.";
 
+const char kSearchIconToggleName[] = "Change the icon for the search button";
+const char kSearchIconToggleDescription[] =
+    "Different icons for the search button.";
+
 const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
 const char kUseDdljsonApiDescription[] =
     "Enables the new ddljson API to fetch Doodles for the NTP.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 39567187..c0ce213 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -123,6 +123,10 @@
 extern const char kUIRefreshPhase1Name[];
 extern const char kUIRefreshPhase1Description[];
 
+// Title and description for the flag to toggle the flag of the search button.
+extern const char kSearchIconToggleName[];
+extern const char kSearchIconToggleDescription[];
+
 // Title and description for the flag to enable the ddljson Doodle API.
 extern const char kUseDdljsonApiName[];
 extern const char kUseDdljsonApiDescription[];
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 54de21bb..562bdb3 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -42,6 +42,8 @@
     "password_manager_internals_service_factory.h",
     "password_tab_helper.h",
     "password_tab_helper.mm",
+    "passwords_directory_util.h",
+    "passwords_directory_util.mm",
     "update_password_infobar_controller.h",
     "update_password_infobar_controller.mm",
   ]
@@ -122,6 +124,7 @@
     "js_credential_manager_unittest.mm",
     "password_controller_js_unittest.mm",
     "password_controller_unittest.mm",
+    "passwords_directory_util_unittest.mm",
     "test_helpers.cc",
     "test_helpers.h",
   ]
diff --git a/ios/chrome/browser/passwords/passwords_directory_util.h b/ios/chrome/browser/passwords/passwords_directory_util.h
new file mode 100644
index 0000000..bc625370
--- /dev/null
+++ b/ios/chrome/browser/passwords/passwords_directory_util.h
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_PASSWORDS_PASSWORDS_DIRECTORY_UTIL_H_
+#define IOS_CHROME_BROWSER_PASSWORDS_PASSWORDS_DIRECTORY_UTIL_H_
+
+#import <Foundation/Foundation.h>
+
+// Returns the URL to the passwords directory.
+NSURL* GetPasswordsDirectoryURL();
+
+// Asynchronously deletes the temporary passwords directory.
+void DeletePasswordsDirectory();
+
+#endif  // IOS_CHROME_BROWSER_PASSWORDS_PASSWORDS_DIRECTORY_UTIL_H_
diff --git a/ios/chrome/browser/passwords/passwords_directory_util.mm b/ios/chrome/browser/passwords/passwords_directory_util.mm
new file mode 100644
index 0000000..13132602
--- /dev/null
+++ b/ios/chrome/browser/passwords/passwords_directory_util.mm
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/passwords/passwords_directory_util.h"
+
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Synchronously deletes passwords directoy.
+void DeletePasswordsDirectorySync() {
+  NSFileManager* file_manager = [NSFileManager defaultManager];
+  base::AssertBlockingAllowed();
+  NSURL* passwords_directory = GetPasswordsDirectoryURL();
+  [file_manager removeItemAtURL:passwords_directory error:nil];
+}
+}  // namespace
+
+NSURL* GetPasswordsDirectoryURL() {
+  return [[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]
+      URLByAppendingPathComponent:@"passwords"
+                      isDirectory:YES];
+}
+
+void DeletePasswordsDirectory() {
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BACKGROUND},
+                           base::BindOnce(&DeletePasswordsDirectorySync));
+}
diff --git a/ios/chrome/browser/passwords/passwords_directory_util_unittest.mm b/ios/chrome/browser/passwords/passwords_directory_util_unittest.mm
new file mode 100644
index 0000000..06417f0
--- /dev/null
+++ b/ios/chrome/browser/passwords/passwords_directory_util_unittest.mm
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/passwords/passwords_directory_util.h"
+
+#include "base/mac/bind_objc_block.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/test/scoped_task_environment.h"
+#import "ios/testing/wait_util.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using testing::WaitUntilConditionOrTimeout;
+using testing::kWaitForFileOperationTimeout;
+
+using PasswordsDirectoryUtilTest = PlatformTest;
+
+// Tests that DeletePasswordsDirectory() actually deletes the directory.
+TEST_F(PasswordsDirectoryUtilTest, Deletion) {
+  base::test::ScopedTaskEnvironment environment;
+
+  NSURL* directory_url = GetPasswordsDirectoryURL();
+  NSURL* file_url =
+      [directory_url URLByAppendingPathComponent:@"TestPasswords.csv"];
+
+  // Create a new file in the passwords  directory.
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+      base::BindBlockArc(^() {
+        NSFileManager* file_manager = [NSFileManager defaultManager];
+        if ([file_manager createDirectoryAtURL:directory_url
+                   withIntermediateDirectories:NO
+                                    attributes:nil
+                                         error:nil]) {
+          [@"test" writeToURL:file_url
+                   atomically:YES
+                     encoding:NSUTF8StringEncoding
+                        error:nil];
+        }
+      }));
+
+  // Verify that the file was created in the passwords directory.
+  EXPECT_TRUE(
+      WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^bool() {
+        return [[NSFileManager defaultManager] fileExistsAtPath:file_url.path];
+      }));
+
+  // Delete download directory.
+  DeletePasswordsDirectory();
+
+  // Verify passwords directory deletion.
+  EXPECT_TRUE(
+      WaitUntilConditionOrTimeout(kWaitForFileOperationTimeout, ^bool() {
+        return ![[NSFileManager defaultManager] fileExistsAtPath:file_url.path];
+      }));
+}
diff --git a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
index 57782a8..f16bc419 100644
--- a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
+++ b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
@@ -127,7 +127,7 @@
 // Checks that the offline URLs are correctly detected by |IsOfflineURL|.
 TEST_F(OfflineURLUtilsTest, IsOfflineURLValid) {
   auto reading_list_model = std::make_unique<ReadingListModelImpl>(
-      nullptr, nullptr, std::make_unique<base::DefaultClock>());
+      nullptr, nullptr, base::DefaultClock::GetInstance());
   GURL entry_url("http://entry_url.com");
   base::FilePath distilled_path("distilled/page.html");
   GURL distilled_url("http://distilled_url.com");
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
index 34d8c11..8520574 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -72,9 +72,9 @@
   std::unique_ptr<ReadingListStore> store = std::make_unique<ReadingListStore>(
       std::move(store_factory), std::move(change_processor));
   std::unique_ptr<KeyedService> reading_list_model =
-      std::make_unique<ReadingListModelImpl>(
-          std::move(store), chrome_browser_state->GetPrefs(),
-          std::make_unique<base::DefaultClock>());
+      std::make_unique<ReadingListModelImpl>(std::move(store),
+                                             chrome_browser_state->GetPrefs(),
+                                             base::DefaultClock::GetInstance());
   return reading_list_model;
 }
 
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
index 57165b8..175b178 100644
--- a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
+++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
@@ -73,7 +73,7 @@
     test_navigation_manager->SetLastCommittedItem(last_committed_item_.get());
     test_web_state_.SetNavigationManager(std::move(test_navigation_manager));
     reading_list_model_ = std::make_unique<ReadingListModelImpl>(
-        nullptr, nullptr, std::make_unique<base::DefaultClock>());
+        nullptr, nullptr, base::DefaultClock::GetInstance());
     reading_list_model_->AddEntry(GURL(kTestURL), kTestTitle,
                                   reading_list::ADDED_VIA_CURRENT_APP);
     ReadingListWebStateObserver::CreateForWebState(&test_web_state_,
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
index 515f3631..9ef5f91c 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
@@ -112,8 +112,11 @@
 + (void)configureLabel:(UILabel*)label withText:(NSString*)text {
   label.numberOfLines = 0;
   label.textColor = [[MDCPalette greyPalette] tint700];
-  label.font = [MDCTypography italicFontFromFont:[MDCTypography captionFont]];
-
+  if (IsUIRefreshPhase1Enabled()) {
+    label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
+  } else {
+    label.font = [MDCTypography italicFontFromFont:[MDCTypography captionFont]];
+  }
   NSRange linkRange;
   NSString* strippedText = ParseStringWithLink(text, &linkRange);
   DCHECK_NE(NSNotFound, static_cast<NSInteger>(linkRange.location));
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
index 7f030985..493fee8 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
index 26eb094..7e8d58fd 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
index 03c4891..c8f74382 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
index 876967a..d39308eb 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
index 55bb241b..6b969b8 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
index 3ecd1c0..5e74f92 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile.png
index ed7c2c73..a985c6d79 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@2x.png
index 2fed774..0eae375 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@3x.png
index dad591d4..fe85862 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_most_visited_tile.imageset/ntp_most_visited_tile@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
index a5bad5a..1642596 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
index 84a9903..c910398 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
index 7cc475c..4a2f3c5 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
index 1585c9b..a292264e6 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
index c2aea652..2b24f9f 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
index 2c2f5f7..9d80c02c 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
index b2134f1..4c55ed4b 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
@@ -83,8 +83,9 @@
 }
 
 - (void)addViewsToSearchField:(UIView*)searchField {
-  UIBlurEffect* blurEffect = [[ToolbarButtonFactory alloc] initWithStyle:NORMAL]
-                                 .toolbarConfiguration.blurEffect;
+  ToolbarButtonFactory* buttonFactory =
+      [[ToolbarButtonFactory alloc] initWithStyle:NORMAL];
+  UIBlurEffect* blurEffect = buttonFactory.toolbarConfiguration.blurEffect;
   UIVisualEffectView* blur =
       [[UIVisualEffectView alloc] initWithEffect:blurEffect];
   blur.layer.cornerRadius = kAdaptiveLocationBarCornerRadius;
@@ -92,12 +93,20 @@
   blur.translatesAutoresizingMaskIntoConstraints = NO;
   AddSameConstraints(blur, searchField);
 
+  UIVisualEffect* vibrancy = [buttonFactory.toolbarConfiguration
+      vibrancyEffectForBlurEffect:blurEffect];
+  UIVisualEffectView* vibrancyView =
+      [[UIVisualEffectView alloc] initWithEffect:vibrancy];
+  [searchField insertSubview:vibrancyView atIndex:1];
+  vibrancyView.translatesAutoresizingMaskIntoConstraints = NO;
+  AddSameConstraints(vibrancyView, searchField);
+
   UIView* backgroundContainer = [[UIView alloc] init];
   backgroundContainer.userInteractionEnabled = NO;
   backgroundContainer.backgroundColor =
       UIColorFromRGB(content_suggestions::kSearchFieldBackgroundColor);
   backgroundContainer.layer.cornerRadius = kAdaptiveLocationBarCornerRadius;
-  [searchField insertSubview:backgroundContainer atIndex:1];
+  [vibrancyView.contentView addSubview:backgroundContainer];
 
   backgroundContainer.translatesAutoresizingMaskIntoConstraints = NO;
   self.backgroundLeadingConstraint = [backgroundContainer.leadingAnchor
@@ -116,7 +125,7 @@
 
   UIImage* search_icon = [UIImage imageNamed:@"ntp_search_icon"];
   UIImageView* search_view = [[UIImageView alloc] initWithImage:search_icon];
-  [searchField addSubview:search_view];
+  [vibrancyView.contentView addSubview:search_view];
   search_view.translatesAutoresizingMaskIntoConstraints = NO;
   [NSLayoutConstraint activateConstraints:@[
     [search_view.centerYAnchor
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index 8ce2b13..cdab6e4 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -227,6 +227,9 @@
 - (void)downloadManagerViewControllerDidClose:
     (DownloadManagerViewController*)controller {
   if (_downloadTask->GetState() != web::DownloadTask::State::kInProgress) {
+    UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadFileResult",
+                              DownloadFileResult::NotStarted,
+                              DownloadFileResult::Count);
     [self cancelDownload];
     return;
   }
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
index cbc619a..c8ef594 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
@@ -305,6 +305,10 @@
   EXPECT_EQ(0U, base_view_controller_.childViewControllers.count);
   EXPECT_FALSE(coordinator_.downloadTask);
   EXPECT_EQ(web::DownloadTask::State::kCancelled, task.GetState());
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileResult",
+      static_cast<base::HistogramBase::Sample>(DownloadFileResult::NotStarted),
+      1);
 }
 
 // Tests presenting Install Google Drive dialog. Coordinator presents StoreKit
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 35317cb..2cc8e3e8 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
 
 #include "base/logging.h"
+#include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
@@ -769,6 +770,15 @@
   if (tapGesture.state == UIGestureRecognizerStateEnded) {
     [self toggleExpansionOfSectionIdentifier:
               self.lastTappedHeaderSectionIdentifier];
+
+    // Highlight the section header being tapped.
+    NSInteger section = [self.tableViewModel
+        sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
+    UITableViewHeaderFooterView* headerView =
+        [self.tableView headerViewForSection:section];
+    TableViewTextHeaderFooterView* headerTextView =
+        base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerView);
+    [headerTextView animateHighlight];
   }
 }
 
@@ -817,6 +827,15 @@
       return;
     }
 
+    // Highlight the section header being long pressed.
+    NSInteger section = [self.tableViewModel
+        sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
+    UITableViewHeaderFooterView* headerView =
+        [self.tableView headerViewForSection:section];
+    TableViewTextHeaderFooterView* headerTextView =
+        base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerView);
+    [headerTextView animateHighlight];
+
     web::ContextMenuParams params;
     // Get view coordinates in local space.
     CGPoint viewCoordinate = [longPressGesture locationInView:self.tableView];
diff --git a/ios/chrome/browser/ui/popup_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/BUILD.gn
index d2b39b1..0a28388 100644
--- a/ios/chrome/browser/ui/popup_menu/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/BUILD.gn
@@ -18,6 +18,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/popup_menu/cells",
+    "//ios/chrome/browser/ui/tools_menu/public",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list",
     "//ios/public/provider/chrome/browser",
@@ -52,6 +53,7 @@
     "//ios/chrome/browser/ui/popup_menu/cells",
     "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/table_view",
+    "//ios/chrome/browser/ui/table_view:styler",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/popup_menu/cells/BUILD.gn b/ios/chrome/browser/ui/popup_menu/cells/BUILD.gn
index f1cf3a3..5d0dcad7 100644
--- a/ios/chrome/browser/ui/popup_menu/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/cells/BUILD.gn
@@ -5,6 +5,8 @@
 source_set("cells") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "popup_menu_footer_item.h",
+    "popup_menu_footer_item.mm",
     "popup_menu_item.h",
     "popup_menu_navigation_item.h",
     "popup_menu_navigation_item.mm",
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.h b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.h
new file mode 100644
index 0000000..546d47d8
--- /dev/null
+++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.h
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_POPUP_MENU_CELLS_POPUP_MENU_FOOTER_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_POPUP_MENU_CELLS_POPUP_MENU_FOOTER_ITEM_H_
+
+#import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h"
+
+// Item for a popup menu footer.
+@interface PopupMenuFooterItem : TableViewHeaderFooterItem
+
+@end
+
+// Associated footer for the PopupMenuFooterItem.
+@interface PopupMenuFooterCell : UITableViewHeaderFooterView
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_POPUP_MENU_CELLS_POPUP_MENU_FOOTER_ITEM_H_
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.mm b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.mm
new file mode 100644
index 0000000..796cd0a
--- /dev/null
+++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.mm
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kSeparatorHeight = 2;
+const CGFloat kSeparatorMargin = 12;
+}  // namespace
+
+@implementation PopupMenuFooterItem
+
+- (instancetype)initWithType:(NSInteger)type {
+  self = [super initWithType:type];
+  if (self) {
+    self.cellClass = [PopupMenuFooterCell class];
+  }
+  return self;
+}
+
+- (void)configureHeaderFooterView:(PopupMenuFooterCell*)footer
+                       withStyler:(ChromeTableViewStyler*)styler {
+  [super configureHeaderFooterView:footer withStyler:styler];
+  // By default the table view footers have a background view. Remove it so it
+  // is transparent.
+  footer.backgroundView = nil;
+}
+
+@end
+
+#pragma mark - PopupMenuFooterCell
+
+@implementation PopupMenuFooterCell
+
+- (instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier {
+  self = [super initWithReuseIdentifier:reuseIdentifier];
+  if (self) {
+    UIView* separator = [[UIView alloc] init];
+    separator.translatesAutoresizingMaskIntoConstraints = NO;
+    separator.backgroundColor = [UIColor lightGrayColor];
+    [self.contentView addSubview:separator];
+    [NSLayoutConstraint activateConstraints:@[
+      [separator.heightAnchor constraintEqualToConstant:kSeparatorHeight],
+      [separator.trailingAnchor
+          constraintEqualToAnchor:self.contentView.trailingAnchor
+                         constant:-kSeparatorMargin],
+      [separator.leadingAnchor
+          constraintEqualToAnchor:self.contentView.leadingAnchor
+                         constant:kSeparatorMargin],
+      [separator.centerYAnchor
+          constraintEqualToAnchor:self.contentView.centerYAnchor],
+    ]];
+  }
+  return self;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
index 986734d..2196e22 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -79,7 +79,8 @@
 
 - (void)showToolsMenuPopup {
   PopupMenuTableViewController* tableViewController =
-      [[PopupMenuTableViewController alloc] init];
+      [[PopupMenuTableViewController alloc]
+          initWithStyle:UITableViewStyleGrouped];
   tableViewController.dispatcher =
       static_cast<id<ApplicationCommands, BrowserCommands>>(self.dispatcher);
   tableViewController.baseViewController = self.baseViewController;
@@ -94,12 +95,18 @@
 }
 
 - (void)showTabGridButtonPopup {
-  UIViewController* viewController = [[UIViewController alloc] init];
-  UILabel* label = [[UILabel alloc] init];
-  label.text = @"TabGrid";
-  viewController.view = label;
-  // TODO(crbug.com/821560): Use the tab grid menu instead of a label.
-  [self presentPopupForContent:viewController fromNamedGuide:kTabSwitcherGuide];
+  PopupMenuTableViewController* tableViewController =
+      [[PopupMenuTableViewController alloc] init];
+  tableViewController.dispatcher =
+      static_cast<id<ApplicationCommands, BrowserCommands>>(self.dispatcher);
+  tableViewController.baseViewController = self.baseViewController;
+
+  self.mediator = [[PopupMenuMediator alloc] initWithType:PopupMenuTypeTabGrid];
+  self.mediator.webStateList = self.webStateList;
+  self.mediator.popupMenu = tableViewController;
+
+  [self presentPopupForContent:tableViewController
+                fromNamedGuide:kTabSwitcherGuide];
 }
 
 - (void)searchButtonPopup {
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index 23034e3..5b213a7 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_item.h"
 #import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_tools_item.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.h"
+#include "ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -26,11 +27,14 @@
 #endif
 
 namespace {
-PopupMenuToolsItem* CreateTableViewItem(int titleID, PopupMenuAction action) {
+PopupMenuToolsItem* CreateTableViewItem(int titleID,
+                                        PopupMenuAction action,
+                                        NSString* accessibilityID) {
   PopupMenuToolsItem* item =
       [[PopupMenuToolsItem alloc] initWithType:kItemTypeEnumZero];
   item.title = l10n_util::GetNSString(titleID);
   item.actionIdentifier = action;
+  item.accessibilityIdentifier = accessibilityID;
   return item;
 }
 }
@@ -213,6 +217,7 @@
       case PopupMenuTypeNavigationBackward:
         break;
       case PopupMenuTypeTabGrid:
+        self.items = @[ [self itemsForNewTab] ];
         break;
       case PopupMenuTypeSearch:
         break;
@@ -242,9 +247,11 @@
   if ([self isPageLoading]) {
     self.reloadStop.title = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_STOP);
     self.reloadStop.actionIdentifier = PopupMenuActionStop;
+    self.reloadStop.accessibilityIdentifier = kToolsMenuStop;
   } else {
     self.reloadStop.title = l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_RELOAD);
     self.reloadStop.actionIdentifier = PopupMenuActionReload;
+    self.reloadStop.accessibilityIdentifier = kToolsMenuReload;
   }
 
   // Reload the items.
@@ -280,8 +287,8 @@
 // Creates the menu items for the tools menu.
 - (void)createToolsMenuItem {
   // Reload or stop page action, created as reload.
-  self.reloadStop =
-      CreateTableViewItem(IDS_IOS_TOOLS_MENU_RELOAD, PopupMenuActionReload);
+  self.reloadStop = CreateTableViewItem(
+      IDS_IOS_TOOLS_MENU_RELOAD, PopupMenuActionReload, kToolsMenuReload);
 
   NSArray* tabActions = [@[ self.reloadStop ]
       arrayByAddingObjectsFromArray:[self itemsForNewTab]];
@@ -295,12 +302,14 @@
 
 - (NSArray<TableViewItem*>*)itemsForNewTab {
   // Open New Tab.
-  TableViewItem* openNewTabItem = CreateTableViewItem(
-      IDS_IOS_TOOLS_MENU_NEW_TAB, PopupMenuActionOpenNewTab);
+  TableViewItem* openNewTabItem =
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_NEW_TAB, PopupMenuActionOpenNewTab,
+                          kToolsMenuNewTabId);
 
   // Open New Incogntio Tab.
   TableViewItem* openNewIncognitoTabItem = CreateTableViewItem(
-      IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB, PopupMenuActionOpenNewIncognitoTab);
+      IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB, PopupMenuActionOpenNewIncognitoTab,
+      kToolsMenuNewIncognitoTabId);
 
   return @[ openNewTabItem, openNewIncognitoTabItem ];
 }
@@ -308,19 +317,22 @@
 - (NSArray<TableViewItem*>*)actionItems {
   NSMutableArray* actionsArray = [NSMutableArray array];
   // Read Later.
-  self.readLater = CreateTableViewItem(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST,
-                                       PopupMenuActionReadLater);
+  self.readLater =
+      CreateTableViewItem(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST,
+                          PopupMenuActionReadLater, kToolsMenuReadLater);
   [actionsArray addObject:self.readLater];
 
   // Find in Pad.
-  self.findInPage = CreateTableViewItem(IDS_IOS_TOOLS_MENU_FIND_IN_PAGE,
-                                        PopupMenuActionFindInPage);
+  self.findInPage =
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_FIND_IN_PAGE,
+                          PopupMenuActionFindInPage, kToolsMenuFindInPageId);
   [actionsArray addObject:self.findInPage];
 
   if ([self userAgentType] != web::UserAgentType::DESKTOP) {
     // Request Desktop Site.
     PopupMenuToolsItem* requestDesktopSite = CreateTableViewItem(
-        IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE, PopupMenuActionRequestDesktop);
+        IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE, PopupMenuActionRequestDesktop,
+        kToolsMenuRequestDesktopId);
     // Disable the action if the user agent is not mobile.
     requestDesktopSite.enabled =
         [self userAgentType] == web::UserAgentType::MOBILE;
@@ -328,13 +340,15 @@
   } else {
     // Request Mobile Site.
     TableViewItem* requestMobileSite = CreateTableViewItem(
-        IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE, PopupMenuActionRequestMobile);
+        IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE, PopupMenuActionRequestMobile,
+        kToolsMenuRequestMobileId);
     [actionsArray addObject:requestMobileSite];
   }
 
   // Site Information.
   self.siteInformation = CreateTableViewItem(
-      IDS_IOS_TOOLS_MENU_SITE_INFORMATION, PopupMenuActionSiteInformation);
+      IDS_IOS_TOOLS_MENU_SITE_INFORMATION, PopupMenuActionSiteInformation,
+      kToolsMenuSiteInformation);
   [actionsArray addObject:self.siteInformation];
 
   // Report an Issue.
@@ -342,13 +356,14 @@
           ->GetUserFeedbackProvider()
           ->IsUserFeedbackEnabled()) {
     TableViewItem* reportIssue = CreateTableViewItem(
-        IDS_IOS_OPTIONS_REPORT_AN_ISSUE, PopupMenuActionReportIssue);
+        IDS_IOS_OPTIONS_REPORT_AN_ISSUE, PopupMenuActionReportIssue,
+        kToolsMenuReportAnIssueId);
     [actionsArray addObject:reportIssue];
   }
 
   // Help.
-  TableViewItem* help =
-      CreateTableViewItem(IDS_IOS_TOOLS_MENU_HELP_MOBILE, PopupMenuActionHelp);
+  TableViewItem* help = CreateTableViewItem(
+      IDS_IOS_TOOLS_MENU_HELP_MOBILE, PopupMenuActionHelp, kToolsMenuHelpId);
   [actionsArray addObject:help];
 
   return actionsArray;
@@ -356,24 +371,28 @@
 
 - (NSArray<TableViewItem*>*)collectionItems {
   // Bookmarks.
-  TableViewItem* bookmarks = CreateTableViewItem(IDS_IOS_TOOLS_MENU_BOOKMARKS,
-                                                 PopupMenuActionBookmarks);
+  TableViewItem* bookmarks =
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_BOOKMARKS,
+                          PopupMenuActionBookmarks, kToolsMenuBookmarksId);
 
   // Reading List.
-  TableViewItem* readingList = CreateTableViewItem(
-      IDS_IOS_TOOLS_MENU_READING_LIST, PopupMenuActionReadingList);
+  TableViewItem* readingList =
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_READING_LIST,
+                          PopupMenuActionReadingList, kToolsMenuReadingListId);
 
   // Recent Tabs.
-  TableViewItem* recentTabs = CreateTableViewItem(
-      IDS_IOS_TOOLS_MENU_RECENT_TABS, PopupMenuActionRecentTabs);
+  TableViewItem* recentTabs =
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_RECENT_TABS,
+                          PopupMenuActionRecentTabs, kToolsMenuOtherDevicesId);
 
   // History.
-  TableViewItem* history =
-      CreateTableViewItem(IDS_IOS_TOOLS_MENU_HISTORY, PopupMenuActionHistory);
+  TableViewItem* history = CreateTableViewItem(
+      IDS_IOS_TOOLS_MENU_HISTORY, PopupMenuActionHistory, kToolsMenuHistoryId);
 
   // Settings.
   TableViewItem* settings =
-      CreateTableViewItem(IDS_IOS_TOOLS_MENU_SETTINGS, PopupMenuActionSettings);
+      CreateTableViewItem(IDS_IOS_TOOLS_MENU_SETTINGS, PopupMenuActionSettings,
+                          kToolsMenuSettingsId);
 
   return @[ bookmarks, readingList, recentTabs, history, settings ];
 }
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_presenter.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_presenter.mm
index e4a1c0f..fc8ff09 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_presenter.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_presenter.mm
@@ -17,7 +17,7 @@
 namespace {
 const CGFloat kMinHeight = 200;
 const CGFloat kMinWidth = 200;
-const CGFloat kMaxWidth = 250;
+const CGFloat kMaxWidth = 300;
 const CGFloat kMaxHeight = 400;
 const CGFloat kMinMargin = 16;
 }  // namespace
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
index 49b5abd0..3bb4b35f 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
@@ -9,7 +9,9 @@
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_footer_item.h"
 #import "ios/chrome/browser/ui/popup_menu/cells/popup_menu_item.h"
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -17,6 +19,10 @@
 
 using base::UserMetricsAction;
 
+namespace {
+const CGFloat kFooterHeight = 30;
+}  // namespace
+
 @implementation PopupMenuTableViewController
 
 @dynamic tableViewModel;
@@ -26,11 +32,16 @@
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
+  self.styler.tableViewBackgroundColor = nil;
   [super viewDidLoad];
   self.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.sectionHeaderHeight = 0;
-  self.tableView.sectionFooterHeight = 0;
   self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+  // Adding a tableHeaderView is needed to prevent a wide inset on top of the
+  // collection.
+  self.tableView.tableHeaderView = [[UIView alloc]
+      initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width,
+                               0.01f)];
 }
 
 - (void)setPopupMenuItems:
@@ -43,6 +54,14 @@
       [self.tableViewModel addItem:item
            toSectionWithIdentifier:sectionIdentifier];
     }
+
+    if (section != items.count - 1) {
+      // Add a footer for all sections except the last one.
+      TableViewHeaderFooterItem* footer =
+          [[PopupMenuFooterItem alloc] initWithType:kItemTypeEnumZero];
+      [self.tableViewModel setFooter:footer
+            forSectionWithIdentifier:sectionIdentifier];
+    }
   }
   [self.tableView reloadData];
 }
@@ -75,6 +94,13 @@
   [self executeActionForIdentifier:item.actionIdentifier origin:center];
 }
 
+- (CGFloat)tableView:(UITableView*)tableView
+    heightForFooterInSection:(NSInteger)section {
+  if (section == self.tableViewModel.numberOfSections - 1)
+    return 0;
+  return kFooterHeight;
+}
+
 #pragma mark - Private
 
 // Executes the action associated with |identifier|, using |origin| as the point
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_view_controller.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_view_controller.mm
index 14331ff..1c8f6ec 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_view_controller.mm
@@ -16,6 +16,8 @@
 const CGFloat kShadowRadius = 10;
 const CGFloat kShadowOpacity = 0.3;
 const CGFloat kContentMargin = 8;
+const CGFloat kBlurBackgroundGreyScale = 0.98;
+const CGFloat kBlurBackgroundAlpha = 0.75;
 }  // namespace
 
 @interface PopupMenuViewController ()<UIGestureRecognizerDelegate>
@@ -56,14 +58,33 @@
 // Sets the content container view up.
 - (void)setUpContentContainer {
   _contentContainer = [[UIView alloc] init];
-  _contentContainer.backgroundColor = [UIColor whiteColor];
+
+  if (UIAccessibilityIsReduceTransparencyEnabled()) {
+    _contentContainer.backgroundColor =
+        [UIColor colorWithWhite:kBlurBackgroundGreyScale alpha:1];
+  } else {
+    _contentContainer.backgroundColor = [UIColor clearColor];
+    UIBlurEffect* blurEffect =
+        [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
+    UIVisualEffectView* blur =
+        [[UIVisualEffectView alloc] initWithEffect:blurEffect];
+    blur.contentView.backgroundColor =
+        [UIColor colorWithWhite:kBlurBackgroundGreyScale
+                          alpha:kBlurBackgroundAlpha];
+    [_contentContainer addSubview:blur];
+    blur.translatesAutoresizingMaskIntoConstraints = NO;
+    blur.layer.cornerRadius = kCornerRadius;
+    blur.layer.masksToBounds = YES;
+    AddSameConstraints(blur, _contentContainer);
+  }
+
   _contentContainer.layer.cornerRadius = kCornerRadius;
   _contentContainer.layer.shadowRadius = kShadowRadius;
   _contentContainer.layer.shadowOpacity = kShadowOpacity;
   _contentContainer.translatesAutoresizingMaskIntoConstraints = NO;
   _contentContainer.layoutMargins = UIEdgeInsetsMake(
       kContentMargin, kContentMargin, kContentMargin, kContentMargin);
-  // TODO(crbug.com/821765): Add blur effect and update the shadow.
+  // TODO(crbug.com/821765): Add update the shadow.
   [self.view addSubview:_contentContainer];
 }
 
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
index 09e1b07..223713be 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
@@ -58,7 +58,7 @@
         .WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult()));
 
     reading_list_model_.reset(new ReadingListModelImpl(
-        nullptr, nullptr, std::make_unique<base::DefaultClock>()));
+        nullptr, nullptr, base::DefaultClock::GetInstance()));
     large_icon_service_.reset(new favicon::LargeIconService(
         &mock_favicon_service_, /*image_fetcher=*/nullptr));
     mediator_ =
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_coordinator_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_coordinator_unittest.mm
index a9e9f70..026546b 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_coordinator_unittest.mm
@@ -115,7 +115,7 @@
     browser_state_ = builder.Build();
 
     reading_list_model_.reset(new ReadingListModelImpl(
-        nullptr, nullptr, std::make_unique<base::DefaultClock>()));
+        nullptr, nullptr, base::DefaultClock::GetInstance()));
     large_icon_service_.reset(new favicon::LargeIconService(
         &mock_favicon_service_, /*image_fetcher=*/nullptr));
     mediator_ =
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
index 3c4da76..3ec70e1 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
@@ -30,11 +30,7 @@
 class ReadingListMediatorTest : public PlatformTest {
  public:
   ReadingListMediatorTest() {
-    std::unique_ptr<base::SimpleTestClock> clock =
-        std::make_unique<base::SimpleTestClock>();
-    clock_ = clock.get();
-    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr,
-                                                    std::move(clock));
+    model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr, &clock_);
     EXPECT_CALL(mock_favicon_service_,
                 GetLargestRawFaviconForPageURL(_, _, _, _, _))
         .WillRepeatedly(
@@ -49,10 +45,10 @@
     model_->SetReadStatus(GURL("http://chromium.org/read1"), true);
     model_->AddEntry(GURL("http://chromium.org/unread2"), "unread2",
                      reading_list::ADDED_VIA_CURRENT_APP);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(no_title_entry_url_, "",
                      reading_list::ADDED_VIA_CURRENT_APP);
-    clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(10));
     model_->AddEntry(GURL("http://chromium.org/read2"), "read2",
                      reading_list::ADDED_VIA_CURRENT_APP);
     model_->SetReadStatus(GURL("http://chromium.org/read2"), true);
@@ -69,7 +65,7 @@
   testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
   std::unique_ptr<ReadingListModelImpl> model_;
   ReadingListMediator* mediator_;
-  base::SimpleTestClock* clock_;
+  base::SimpleTestClock clock_;
   GURL no_title_entry_url_;
   std::unique_ptr<favicon::LargeIconService> large_icon_service_;
 
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 54b9e11..ad2f11f 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -363,6 +363,7 @@
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/authentication:authentication_ui",
     "//ios/chrome/browser/ui/authentication:eg_test_support",
     "//ios/chrome/browser/ui/settings:test_support",
diff --git a/ios/chrome/browser/ui/settings/password_exporter.h b/ios/chrome/browser/ui/settings/password_exporter.h
index 4d39f82..83c699e 100644
--- a/ios/chrome/browser/ui/settings/password_exporter.h
+++ b/ios/chrome/browser/ui/settings/password_exporter.h
@@ -96,6 +96,9 @@
 // Called when the user cancels the export operation.
 - (void)cancelExport;
 
+// Called to re-enable export functionality when the export UI flow finishes.
+- (void)resetExportState;
+
 // State of the export operation.
 @property(nonatomic, readonly, assign) ExportState exportState;
 
diff --git a/ios/chrome/browser/ui/settings/password_exporter.mm b/ios/chrome/browser/ui/settings/password_exporter.mm
index c7df530..ef8ebe3b 100644
--- a/ios/chrome/browser/ui/settings/password_exporter.mm
+++ b/ios/chrome/browser/ui/settings/password_exporter.mm
@@ -15,6 +15,7 @@
 #include "components/password_manager/core/browser/export/password_csv_writer.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/passwords/passwords_directory_util.h"
 #import "ios/chrome/browser/ui/settings/reauthentication_module.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -62,6 +63,17 @@
   WriteToURLStatus (^writeToFile)() = ^() {
     base::AssertBlockingAllowed();
     NSError* error = nil;
+
+    NSURL* directoryURL = [fileURL URLByDeletingLastPathComponent];
+    NSFileManager* fileManager = [NSFileManager defaultManager];
+
+    if (![fileManager createDirectoryAtURL:directoryURL
+               withIntermediateDirectories:YES
+                                attributes:nil
+                                     error:nil]) {
+      return WriteToURLStatus::UNKNOWN_ERROR;
+    }
+
     BOOL success = [data writeToURL:fileURL
                          atomically:YES
                            encoding:NSUTF8StringEncoding
@@ -258,10 +270,13 @@
     [self resetExportState];
     return;
   }
-  NSURL* tempPasswordsFileURL =
-      [[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]
-          URLByAppendingPathComponent:_tempPasswordsFileName
-                          isDirectory:NO];
+
+  NSURL* uniqueDirectoryURL = [GetPasswordsDirectoryURL()
+      URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]
+                      isDirectory:YES];
+  NSURL* passwordsTempFileURL =
+      [uniqueDirectoryURL URLByAppendingPathComponent:_tempPasswordsFileName
+                                          isDirectory:NO];
 
   __weak PasswordExporter* weakSelf = self;
   void (^onFileWritten)(WriteToURLStatus) = ^(WriteToURLStatus status) {
@@ -275,7 +290,7 @@
     }
     switch (status) {
       case WriteToURLStatus::SUCCESS:
-        [strongSelf showActivityView];
+        [strongSelf showActivityView:passwordsTempFileURL];
         break;
       case WriteToURLStatus::OUT_OF_DISK_SPACE_ERROR:
         [strongSelf
@@ -310,33 +325,26 @@
   self.serializedPasswords = nil;
 
   [_passwordFileWriter writeData:serializedPasswords
-                           toURL:tempPasswordsFileURL
+                           toURL:passwordsTempFileURL
                          handler:onFileWritten];
 }
 
 - (void)deleteTemporaryFile:(NSURL*)passwordsTempFileURL {
-  __weak PasswordExporter* weakSelf = self;
-  base::PostTaskWithTraitsAndReply(
+  NSURL* uniqueDirectoryURL =
+      [passwordsTempFileURL URLByDeletingLastPathComponent];
+  base::PostTaskWithTraits(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
       base::BindBlockArc(^() {
         base::AssertBlockingAllowed();
         NSFileManager* fileManager = [NSFileManager defaultManager];
-        [fileManager removeItemAtURL:passwordsTempFileURL error:nil];
-      }),
-      base::BindBlockArc(^() {
-        [weakSelf resetExportState];
+        [fileManager removeItemAtURL:uniqueDirectoryURL error:nil];
       }));
 }
 
-- (void)showActivityView {
-  NSURL* passwordsTempFileURL =
-      [[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]
-          URLByAppendingPathComponent:_tempPasswordsFileName
-                          isDirectory:NO];
+- (void)showActivityView:(NSURL*)passwordsTempFileURL {
   if (self.exportState == ExportState::CANCELLING) {
-    // Initiate cleanup. Once the file is deleted, the export state will be
-    // reset;
     [self deleteTemporaryFile:passwordsTempFileURL];
+    [self resetExportState];
     return;
   }
   __weak PasswordExporter* weakSelf = self;
diff --git a/ios/chrome/browser/ui/settings/password_exporter_unittest.mm b/ios/chrome/browser/ui/settings/password_exporter_unittest.mm
index 4649600..eb50a32 100644
--- a/ios/chrome/browser/ui/settings/password_exporter_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password_exporter_unittest.mm
@@ -56,6 +56,9 @@
 // error.
 @property(nonatomic, assign) WriteToURLStatus writingStatus;
 
+// Whether a write operation was attempted.
+@property(nonatomic, assign) BOOL writeAttempted;
+
 @end
 
 @implementation FakePasswordFileWriter {
@@ -64,10 +67,20 @@
 }
 
 @synthesize writingStatus = _writingStatus;
+@synthesize writeAttempted = _writeAttempted;
+
+- (instancetype)init {
+  self = [super init];
+  if (self) {
+    _writeAttempted = NO;
+  }
+  return self;
+}
 
 - (void)writeData:(NSString*)data
             toURL:(NSURL*)fileURL
           handler:(void (^)(WriteToURLStatus))handler {
+  _writeAttempted = YES;
   _writeStatusHandler = handler;
 }
 
@@ -104,30 +117,6 @@
     return password_forms;
   }
 
-  void TearDown() override {
-    NSURL* passwords_file_url = GetPasswordsFileURL();
-    if ([[NSFileManager defaultManager]
-            fileExistsAtPath:[passwords_file_url path]]) {
-      [[NSFileManager defaultManager] removeItemAtURL:passwords_file_url
-                                                error:nil];
-    }
-    PlatformTest::TearDown();
-  }
-
-  NSURL* GetPasswordsFileURL() {
-    NSString* passwords_file_name =
-        [l10n_util::GetNSString(IDS_PASSWORD_MANAGER_DEFAULT_EXPORT_FILENAME)
-            stringByAppendingString:@".csv"];
-    return [[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]
-        URLByAppendingPathComponent:passwords_file_name
-                        isDirectory:NO];
-  }
-
-  BOOL PasswordFileExists() {
-    return [[NSFileManager defaultManager]
-        fileExistsAtPath:[GetPasswordsFileURL() path]];
-  }
-
   id password_exporter_delegate_;
   PasswordExporter* password_exporter_;
   MockReauthenticationModule* mock_reauthentication_module_;
@@ -135,14 +124,17 @@
   base::HistogramTester histogram_tester_;
 };
 
-// Tests that when reauthentication is successful, the passwords file is written
-// and showing the activity view is requested.
+// Tests that when reauthentication is successful, writing the passwords file
+// is attempted and a call to show the activity view is made.
 TEST_F(PasswordExporterTest, PasswordFileWriteReauthSucceeded) {
   mock_reauthentication_module_.shouldSucceed = YES;
-  NSURL* passwords_file_url = GetPasswordsFileURL();
+  FakePasswordFileWriter* fake_password_file_writer =
+      [[FakePasswordFileWriter alloc] init];
+  fake_password_file_writer.writingStatus = WriteToURLStatus::SUCCESS;
+  [password_exporter_ setPasswordFileWriter:fake_password_file_writer];
 
   OCMExpect([password_exporter_delegate_
-      showActivityViewWithActivityItems:[OCMArg isEqual:@[ passwords_file_url ]]
+      showActivityViewWithActivityItems:[OCMArg any]
                       completionHandler:[OCMArg any]]);
 
   [password_exporter_ startExportFlow:CreatePasswordList()];
@@ -150,7 +142,11 @@
   // Wait for all asynchronous tasks to complete.
   scoped_task_environment_.RunUntilIdle();
 
-  EXPECT_TRUE(PasswordFileExists());
+  EXPECT_TRUE(fake_password_file_writer.writeAttempted);
+
+  // Execute file write completion handler to continue the flow.
+  [fake_password_file_writer executeHandler];
+
   EXPECT_OCMOCK_VERIFY(password_exporter_delegate_);
 
   histogram_tester_.ExpectTotalCount(
@@ -162,43 +158,6 @@
       "PasswordManager.ExportedPasswordsPerUserInCSV", 1, 1);
 }
 
-// Tests that the exporter becomes idle after the export finishes.
-TEST_F(PasswordExporterTest, ExportIdleAfterFinishing) {
-  mock_reauthentication_module_.shouldSucceed = YES;
-  NSURL* passwords_file_url = GetPasswordsFileURL();
-
-  OCMStub(
-      [password_exporter_delegate_
-          showActivityViewWithActivityItems:[OCMArg
-                                                isEqual:@[ passwords_file_url ]]
-                          completionHandler:[OCMArg any]])
-      .andDo(^(NSInvocation* invocation) {
-        void (^completionHandler)(NSString* activityType, BOOL completed,
-                                  NSArray* returnedItems,
-                                  NSError* activityError);
-        [invocation getArgument:&completionHandler atIndex:3];
-        // Since the completion handler doesn't use any of the
-        // passed in parameters, dummy arguments are passed for
-        // convenience.
-        completionHandler(@"", YES, @[], nil);
-      });
-
-  [password_exporter_ startExportFlow:CreatePasswordList()];
-
-  // Wait for all asynchronous tasks to complete.
-  scoped_task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(ExportState::IDLE, password_exporter_.exportState);
-
-  histogram_tester_.ExpectTotalCount(
-      "PasswordManager.TimeReadingExportedPasswords", 1);
-  histogram_tester_.ExpectUniqueSample(
-      "PasswordManager.ExportPasswordsToCSVResult",
-      password_manager::metrics_util::ExportPasswordsResult::SUCCESS, 1);
-  histogram_tester_.ExpectUniqueSample(
-      "PasswordManager.ExportedPasswordsPerUserInCSV", 1, 1);
-}
-
 // Tests that if the file writing fails because of not enough disk space
 // the appropriate error is displayed and the export operation
 // is interrupted.
@@ -297,6 +256,11 @@
       [[FakePasswordSerialzerBridge alloc] init];
   [password_exporter_
       setPasswordSerializerBridge:fake_password_serializer_bridge];
+
+  FakePasswordFileWriter* fake_password_file_writer =
+      [[FakePasswordFileWriter alloc] init];
+  [password_exporter_ setPasswordFileWriter:fake_password_file_writer];
+
   [[password_exporter_delegate_ reject]
       showActivityViewWithActivityItems:[OCMArg any]
                       completionHandler:[OCMArg any]];
@@ -324,8 +288,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   // Serializing passwords has finished, but reauthentication was not
-  // successful, so the file is not written.
-  EXPECT_FALSE(PasswordFileExists());
+  // successful, so writing the file was not attempted.
+  EXPECT_FALSE(fake_password_file_writer.writeAttempted);
   EXPECT_EQ(ExportState::IDLE, password_exporter_.exportState);
 
   histogram_tester_.ExpectTotalCount(
@@ -346,6 +310,10 @@
   [password_exporter_
       setPasswordSerializerBridge:fake_password_serializer_bridge];
 
+  FakePasswordFileWriter* fake_password_file_writer =
+      [[FakePasswordFileWriter alloc] init];
+  [password_exporter_ setPasswordFileWriter:fake_password_file_writer];
+
   [[password_exporter_delegate_ reject]
       showActivityViewWithActivityItems:[OCMArg any]
                       completionHandler:[OCMArg any]];
@@ -366,7 +334,7 @@
     // is invoked. As this should not happen, mark the test as failed.
     GTEST_FAIL();
   }
-  EXPECT_FALSE(PasswordFileExists());
+  EXPECT_FALSE(fake_password_file_writer.writeAttempted);
   EXPECT_EQ(ExportState::IDLE, password_exporter_.exportState);
 
   histogram_tester_.ExpectTotalCount(
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index dac9efd..5dd5e686 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -24,6 +24,7 @@
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #import "ios/chrome/browser/ui/settings/reauthentication_module.h"
 #include "ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h"
+#include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/password_test_util.h"
@@ -57,6 +58,7 @@
 using chrome_test_util::SettingsMenuBackButton;
 using chrome_test_util::NavigationBarDoneButton;
 using chrome_test_util::SetUpAndReturnMockReauthenticationModule;
+using chrome_test_util::SetUpAndReturnMockReauthenticationModuleForExport;
 
 namespace {
 
@@ -1580,4 +1582,72 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// Test export flow
+- (void)testExportFlow {
+  if (!base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordExport)) {
+    return;
+  }
+  // Saving a form is needed for exporting passwords.
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  MockReauthenticationModule* mock_reauthentication_module =
+      SetUpAndReturnMockReauthenticationModuleForExport();
+  mock_reauthentication_module.shouldSucceed = YES;
+
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_EXPORT_PASSWORDS)]
+      performAction:grey_tap()];
+
+  // Tap the alert's Export passwords... button to confirm. Check
+  // accessibilityTrait to differentiate against the above matching element,
+  // which has UIAccessibilityTraitSelected.
+  // TODO(crbug.com/751311): Revisit and check if there is a better solution to
+  // match the button.
+  id<GREYMatcher> exportConfirmationButton = grey_allOf(
+      ButtonWithAccessibilityLabel(
+          l10n_util::GetNSString(IDS_IOS_EXPORT_PASSWORDS)),
+      grey_not(grey_accessibilityTrait(UIAccessibilityTraitSelected)), nil);
+  [[EarlGrey selectElementWithMatcher:exportConfirmationButton]
+      performAction:grey_tap()];
+
+  // Wait until the alerts are dismissed.
+  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+
+  // Check that export button is disabled
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_EXPORT_PASSWORDS)]
+      assertWithMatcher:grey_accessibilityTrait(
+                            UIAccessibilityTraitNotEnabled)];
+
+  if (IsIPadIdiom()) {
+    // Tap outside the activity view to dismiss it, because it is not
+    // accompanied by a "Cancel" button on iPad.
+    [[EarlGrey selectElementWithMatcher:
+                   chrome_test_util::ButtonWithAccessibilityLabelId(
+                       IDS_IOS_EXPORT_PASSWORDS)] performAction:grey_tap()];
+  } else {
+    // Tap on the "Cancel" button accompanying the activity view to dismiss it.
+    [[EarlGrey
+        selectElementWithMatcher:grey_allOf(
+                                     ButtonWithAccessibilityLabel(@"Cancel"),
+                                     grey_interactable(), nullptr)]
+        performAction:grey_tap()];
+  }
+
+  // Wait until the activity view is dismissed.
+  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+
+  // Check that export button is re-enabled.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_EXPORT_PASSWORDS)]
+      assertWithMatcher:grey_not(grey_accessibilityTrait(
+                            UIAccessibilityTraitNotEnabled))];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index 3c0dc9b..2fcb959 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -127,11 +127,51 @@
 @implementation BlacklistedFormContentItem
 @end
 
+@protocol PasswordExportActivityViewControllerDelegate<NSObject>
+
+// Used to reset the export state when the activity view disappears.
+- (void)resetExport;
+
+@end
+
+@interface PasswordExportActivityViewController : UIActivityViewController
+
+- (PasswordExportActivityViewController*)
+initWithActivityItems:(NSArray*)activityItems
+             delegate:
+                 (id<PasswordExportActivityViewControllerDelegate>)delegate;
+
+@end
+
+@implementation PasswordExportActivityViewController {
+  __weak id<PasswordExportActivityViewControllerDelegate> _weakDelegate;
+}
+
+- (PasswordExportActivityViewController*)
+initWithActivityItems:(NSArray*)activityItems
+             delegate:
+                 (id<PasswordExportActivityViewControllerDelegate>)delegate {
+  self = [super initWithActivityItems:activityItems applicationActivities:nil];
+  if (self) {
+    _weakDelegate = delegate;
+  }
+
+  return self;
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+  [_weakDelegate resetExport];
+  [super viewDidDisappear:animated];
+}
+
+@end
+
 @interface SavePasswordsCollectionViewController ()<
     BooleanObserver,
     PasswordDetailsCollectionViewControllerDelegate,
     SuccessfulReauthTimeAccessor,
-    PasswordExporterDelegate> {
+    PasswordExporterDelegate,
+    PasswordExportActivityViewControllerDelegate> {
   // The observable boolean that binds to the password manager setting state.
   // Saved passwords are only on if the password manager is enabled.
   PrefBackedBoolean* passwordManagerEnabled_;
@@ -516,10 +556,10 @@
   if (enabled) {
     DCHECK(exportReady_ && ![self.editor isEditing]);
     exportPasswordsItem_.textColor = [[MDCPalette greyPalette] tint900];
-    exportPasswordsItem_.accessibilityTraits = UIAccessibilityTraitButton;
+    exportPasswordsItem_.accessibilityTraits &= ~UIAccessibilityTraitNotEnabled;
   } else {
     exportPasswordsItem_.textColor = [[MDCPalette greyPalette] tint500];
-    exportPasswordsItem_.accessibilityTraits = UIAccessibilityTraitNotEnabled;
+    exportPasswordsItem_.accessibilityTraits |= UIAccessibilityTraitNotEnabled;
   }
   [self reconfigureCellsForItems:@[ exportPasswordsItem_ ]];
 }
@@ -858,9 +898,10 @@
                                                     NSArray* returnedItems,
                                                     NSError* activityError))
                                               completionHandler {
-  UIActivityViewController* activityViewController =
-      [[UIActivityViewController alloc] initWithActivityItems:activityItems
-                                        applicationActivities:nil];
+  PasswordExportActivityViewController* activityViewController =
+      [[PasswordExportActivityViewController alloc]
+          initWithActivityItems:activityItems
+                       delegate:self];
   NSArray* excludedActivityTypes = @[
     UIActivityTypeAddToReadingList, UIActivityTypeAirDrop,
     UIActivityTypeCopyToPasteboard, UIActivityTypeOpenInIBooks,
@@ -893,6 +934,14 @@
   [self presentViewController:activityViewController];
 }
 
+#pragma mark - PasswordExportActivityViewControllerDelegate
+
+- (void)resetExport {
+  [self.passwordExporter resetExportState];
+}
+
+#pragma mark Helper methods
+
 - (void)presentViewController:(UIViewController*)viewController {
   if (self.presentedViewController == preparingPasswordsAlert_ &&
       !preparingPasswordsAlert_.beingDismissed) {
@@ -908,8 +957,6 @@
   }
 }
 
-#pragma mark Helper methods
-
 // Sets the save passwords switch item's enabled status to |enabled| and
 // reconfigures the corresponding cell.
 - (void)setSavePasswordsSwitchItemEnabled:(BOOL)enabled {
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
index 3d6a458..62c4f98d 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
@@ -333,14 +333,16 @@
 
   UIColor* disabledColor = [[MDCPalette greyPalette] tint500];
   EXPECT_NSEQ(disabledColor, exportButton.textColor);
-  EXPECT_EQ(UIAccessibilityTraitNotEnabled, exportButton.accessibilityTraits);
+  EXPECT_TRUE(exportButton.accessibilityTraits &
+              UIAccessibilityTraitNotEnabled);
 
   // Add blacklisted form.
   AddBlacklistedForm1();
   // The export button should still be disabled as exporting blacklisted forms
   // is not currently supported.
   EXPECT_NSEQ(disabledColor, exportButton.textColor);
-  EXPECT_EQ(UIAccessibilityTraitNotEnabled, exportButton.accessibilityTraits);
+  EXPECT_TRUE(exportButton.accessibilityTraits &
+              UIAccessibilityTraitNotEnabled);
 }
 
 TEST_P(SavePasswordsCollectionViewControllerTest,
@@ -352,7 +354,8 @@
 
   CheckTextCellTitleWithId(IDS_IOS_EXPORT_PASSWORDS, 3, 0);
   EXPECT_NSEQ([[MDCPalette greyPalette] tint900], exportButton.textColor);
-  EXPECT_NE(UIAccessibilityTraitNotEnabled, exportButton.accessibilityTraits);
+  EXPECT_FALSE(exportButton.accessibilityTraits &
+               UIAccessibilityTraitNotEnabled);
 }
 
 // Tests that the "Export Passwords..." button is greyed out in edit mode.
@@ -371,7 +374,8 @@
       collectionViewWillBeginEditing:save_passwords_controller.collectionView];
 
   EXPECT_NSEQ([[MDCPalette greyPalette] tint500], exportButton.textColor);
-  EXPECT_EQ(UIAccessibilityTraitNotEnabled, exportButton.accessibilityTraits);
+  EXPECT_TRUE(exportButton.accessibilityTraits &
+              UIAccessibilityTraitNotEnabled);
 }
 
 // Tests that the "Export Passwords..." button is enabled after exiting
@@ -393,7 +397,8 @@
       collectionViewWillEndEditing:save_passwords_controller.collectionView];
 
   EXPECT_NSEQ([[MDCPalette greyPalette] tint900], exportButton.textColor);
-  EXPECT_NE(UIAccessibilityTraitNotEnabled, exportButton.accessibilityTraits);
+  EXPECT_FALSE(exportButton.accessibilityTraits &
+               UIAccessibilityTraitNotEnabled);
 }
 
 TEST_P(SavePasswordsCollectionViewControllerTest, PropagateDeletionToStore) {
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
index a8b8bd3d..f9656dc 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h
@@ -19,6 +19,9 @@
 // UITableViewHeaderFooterView that displays a text label.
 @interface TableViewTextHeaderFooterView : UITableViewHeaderFooterView
 @property(nonatomic, readwrite, strong) UILabel* subtitleLabel;
+// Animates a change in the backgroundView color and then changes it back to the
+// original backGround color in order to simulate a selection highlight.
+- (void)animateHighlight;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_TEXT_HEADER_FOOTER_ITEM_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
index 5a9bd8a..e6828f3 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
@@ -48,7 +48,13 @@
 
 #pragma mark - TableViewTextHeaderFooter
 
+@interface TableViewTextHeaderFooterView ()
+// Animator that handles all cell animations.
+@property(strong, nonatomic) UIViewPropertyAnimator* cellAnimator;
+@end
+
 @implementation TableViewTextHeaderFooterView
+@synthesize cellAnimator = _cellAnimator;
 @synthesize subtitleLabel = _subtitleLabel;
 @synthesize textLabel = _textLabel;
 
@@ -108,4 +114,26 @@
   return self;
 }
 
+- (void)animateHighlight {
+  UIColor* originalBackgroundColor = self.contentView.backgroundColor;
+  self.cellAnimator = [[UIViewPropertyAnimator alloc]
+      initWithDuration:0.15
+                 curve:UIViewAnimationCurveLinear
+            animations:^{
+              self.contentView.backgroundColor =
+                  [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
+            }];
+  __weak TableViewTextHeaderFooterView* weakSelf = self;
+  [self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    weakSelf.contentView.backgroundColor = originalBackgroundColor;
+  }];
+  [self.cellAnimator startAnimation];
+}
+
+- (void)prepareForReuse {
+  [super prepareForReuse];
+  if (self.cellAnimator.isRunning)
+    [self.cellAnimator stopAnimation:YES];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
index e141d8f..4b07c33 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
@@ -16,6 +16,7 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.h"
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/third_party/material_components_ios/src/components/ProgressView/src/MaterialProgressView.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
@@ -77,6 +78,7 @@
   [self addLongPressGestureToView:self.view.backButton];
   [self addLongPressGestureToView:self.view.forwardButton];
   [self addLongPressGestureToView:self.view.forwardButtonTrailingPosition];
+  [self addLongPressGestureToView:self.view.tabGridButton];
 }
 
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
@@ -144,6 +146,8 @@
 }
 
 - (void)setSearchIcon:(UIImage*)searchIcon {
+  if (IconForSearchButton() == ToolbarSearchButtonIconMagnifying)
+    return;
   [self.view.omniboxButton setImage:searchIcon forState:UIControlStateNormal];
 }
 
@@ -270,6 +274,8 @@
     } else {
       [self.dispatcher showTabHistoryPopupForForwardHistory];
     }
+  } else if (gesture.view == self.view.tabGridButton) {
+    [self.dispatcher showTabGridButtonPopup];
   }
 }
 
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
index f3d886e..b2f7783 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -96,8 +97,9 @@
   AddSameConstraints(self.blur, self);
 
   UIView* contentView = self;
-  if (UIVisualEffect* vibrancy = [self.buttonFactory.toolbarConfiguration
-          vibrancyEffectForBlurEffect:blurEffect]) {
+  UIVisualEffect* vibrancy = [self.buttonFactory.toolbarConfiguration
+      vibrancyEffectForBlurEffect:blurEffect];
+  if (vibrancy && IconForSearchButton() != ToolbarSearchButtonIconColorful) {
     // Add vibrancy only if we have a vibrancy effect.
     UIVisualEffectView* vibrancyView =
         [[UIVisualEffectView alloc] initWithEffect:vibrancy];
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
index 136ec134c..9460c77b 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
@@ -9,6 +9,13 @@
 
 #include "base/feature_list.h"
 
+// Enum for the different icons for the search button.
+typedef NS_ENUM(NSUInteger, ToolbarSearchButtonIcon) {
+  ToolbarSearchButtonIconGrey,
+  ToolbarSearchButtonIconColorful,
+  ToolbarSearchButtonIconMagnifying,
+};
+
 // Enum for the different positions of the toolbars' buttons.
 typedef NS_ENUM(NSUInteger, ToolbarButtonPosition) {
   ToolbarButtonPositionNavigationBottomNoTop,
@@ -25,4 +32,15 @@
 
 ToolbarButtonPosition PositionForCurrentProcess();
 
+// Switch with the different value for thesearch icon on the bottom adaptive
+// toolbar.
+// TODO(crbug.com/826192): Remove this.
+extern const char kIconSearchButtonSwitch[];
+
+extern const char kIconSearchButtonGrey[];
+extern const char kIconSearchButtonColorful[];
+extern const char kIconSearchButtonMagnifying[];
+
+ToolbarSearchButtonIcon IconForSearchButton();
+
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_CONTROLLER_BASE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
index 385bcce..6d9de2e 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
@@ -31,3 +31,27 @@
   }
   return ToolbarButtonPositionNavigationBottomNoTop;
 }
+
+const char kIconSearchButtonSwitch[] = "icon-search-button-switch";
+
+extern const char kIconSearchButtonGrey[] = "icon-search-button-grey";
+extern const char kIconSearchButtonColorful[] = "icon-search-button-colorful";
+extern const char kIconSearchButtonMagnifying[] =
+    "icon-search-button-magnifying";
+
+ToolbarSearchButtonIcon IconForSearchButton() {
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(kIconSearchButtonSwitch)) {
+    if (command_line->GetSwitchValueASCII(kIconSearchButtonSwitch) ==
+        kIconSearchButtonColorful) {
+      return ToolbarSearchButtonIconColorful;
+    } else if (command_line->GetSwitchValueASCII(kIconSearchButtonSwitch) ==
+               kIconSearchButtonMagnifying) {
+      return ToolbarSearchButtonIconMagnifying;
+    } else {
+      return ToolbarSearchButtonIconGrey;
+    }
+  }
+  return ToolbarSearchButtonIconGrey;
+}
diff --git a/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h b/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h
index 47e2d51..f1bde4c 100644
--- a/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h
+++ b/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.h
@@ -18,6 +18,10 @@
 extern NSString* const kToolsMenuDidHideNotification;
 
 // Tools Menu item IDs.
+// Reload item accessibility Identifier.
+extern NSString* const kToolsMenuReload;
+// Stop item accessibility Identifier.
+extern NSString* const kToolsMenuStop;
 // New Tab item accessibility Identifier.
 extern NSString* const kToolsMenuNewTabId;
 // New incognito Tab item accessibility Identifier.
@@ -46,6 +50,10 @@
 extern NSString* const kToolsMenuHelpId;
 // Request mobile item accessibility Identifier.
 extern NSString* const kToolsMenuRequestMobileId;
+// ReadLater item accessibility Identifier.
+extern NSString* const kToolsMenuReadLater;
+// SiteInformation item accessibility Identifier.
+extern NSString* const kToolsMenuSiteInformation;
 
 // Identifiers for tools menu items (for metrics purposes).
 typedef NS_ENUM(int, ToolsMenuItemID) {
diff --git a/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.mm b/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.mm
index 3db4a03..f6c2f2f6 100644
--- a/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.mm
+++ b/ios/chrome/browser/ui/tools_menu/public/tools_menu_constants.mm
@@ -19,6 +19,8 @@
     @"kToolsMenuDidHideNotification";
 
 // Tools menu item IDs.
+NSString* const kToolsMenuReload = @"kToolsMenuReload";
+NSString* const kToolsMenuStop = @"kToolsMenuStop";
 NSString* const kToolsMenuNewTabId = @"kToolsMenuNewTabId";
 NSString* const kToolsMenuNewIncognitoTabId = @"kToolsMenuNewIncognitoTabId";
 NSString* const kToolsMenuCloseAllTabsId = @"kToolsMenuCloseAllTabsId";
@@ -34,3 +36,5 @@
 NSString* const kToolsMenuSettingsId = @"kToolsMenuSettingsId";
 NSString* const kToolsMenuHelpId = @"kToolsMenuHelpId";
 NSString* const kToolsMenuRequestMobileId = @"kToolsMenuRequestMobileId";
+NSString* const kToolsMenuReadLater = @"kToolsMenuReadLater";
+NSString* const kToolsMenuSiteInformation = @"kToolsMenuSiteInformation";
diff --git a/ios/chrome/browser/ui/user_feedback_features.cc b/ios/chrome/browser/ui/user_feedback_features.cc
index a7af363..72efee457 100644
--- a/ios/chrome/browser/ui/user_feedback_features.cc
+++ b/ios/chrome/browser/ui/user_feedback_features.cc
@@ -5,4 +5,4 @@
 #include "ios/chrome/browser/ui/user_feedback_features.h"
 
 const base::Feature kFeedbackKitV2{"FeedbackKitV2",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
+                                   base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/web/page_placeholder_tab_helper.mm b/ios/chrome/browser/web/page_placeholder_tab_helper.mm
index bcdcbfde..412860a 100644
--- a/ios/chrome/browser/web/page_placeholder_tab_helper.mm
+++ b/ios/chrome/browser/web/page_placeholder_tab_helper.mm
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
+#import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -82,11 +83,17 @@
   // Update placeholder view's image and display it on top of WebState's view.
   __weak UIImageView* weak_placeholder_view = placeholder_view_;
   __weak UIView* weak_web_state_view = web_state_->GetView();
-  // placeholder_view_.image = SnapshotTabHelper::DefautSnapshotImage();
+  __weak id<CRWWebViewProxy> web_view_proxy = web_state_->GetWebViewProxy();
   SnapshotTabHelper::FromWebState(web_state_)
       ->RetrieveGreySnapshot(^(UIImage* snapshot) {
+        CGRect frame = weak_web_state_view.frame;
+        UIEdgeInsets inset = web_view_proxy.contentInset;
+        frame.origin.x += inset.left;
+        frame.origin.y += inset.top;
+        frame.size.width -= (inset.right + inset.left);
+        frame.size.height -= (inset.bottom + inset.top);
+        weak_placeholder_view.frame = frame;
         weak_placeholder_view.image = snapshot;
-        weak_placeholder_view.frame = weak_web_state_view.frame;
         [weak_web_state_view addSubview:weak_placeholder_view];
       });
 
diff --git a/ios/chrome/test/app/password_test_util.h b/ios/chrome/test/app/password_test_util.h
index a586439..cbaf0167 100644
--- a/ios/chrome/test/app/password_test_util.h
+++ b/ios/chrome/test/app/password_test_util.h
@@ -28,6 +28,11 @@
 // blocked with a reauth prompt, and return the fake reauthentication module.
 MockReauthenticationModule* SetUpAndReturnMockReauthenticationModule();
 
+// Replace the reauthentication module in
+// PasswordExporter with a fake one to avoid being
+// blocked with a reauth prompt, and return the fake reauthentication module.
+MockReauthenticationModule* SetUpAndReturnMockReauthenticationModuleForExport();
+
 }  // namespace chrome_test_util
 
 #endif  // IOS_CHROME_TEST_APP_PASSWORD_TEST_UTIL_H_
diff --git a/ios/chrome/test/app/password_test_util.mm b/ios/chrome/test/app/password_test_util.mm
index 734e133..bea449b 100644
--- a/ios/chrome/test/app/password_test_util.mm
+++ b/ios/chrome/test/app/password_test_util.mm
@@ -6,6 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/settings/password_details_collection_view_controller_for_testing.h"
+#import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/browser/ui/util/top_view_controller.h"
 
@@ -60,4 +61,24 @@
   return mock_reauthentication_module;
 }
 
+// Replace the reauthentication module in
+// PasswordExporter with a fake one to avoid being
+// blocked with a reauth prompt, and return the fake reauthentication module.
+MockReauthenticationModule*
+SetUpAndReturnMockReauthenticationModuleForExport() {
+  MockReauthenticationModule* mock_reauthentication_module =
+      [[MockReauthenticationModule alloc] init];
+  // TODO(crbug.com/754642): Stop using TopPresentedViewController();
+  SettingsNavigationController* settings_navigation_controller =
+      base::mac::ObjCCastStrict<SettingsNavigationController>(
+          top_view_controller::TopPresentedViewController());
+  SavePasswordsCollectionViewController*
+      save_passwords_collection_view_controller =
+          base::mac::ObjCCastStrict<SavePasswordsCollectionViewController>(
+              settings_navigation_controller.topViewController);
+  [save_passwords_collection_view_controller
+      setReauthenticationModuleForExporter:mock_reauthentication_module];
+  return mock_reauthentication_module;
+}
+
 }  // namespace
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index 609d047..af5dd0a 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -356,9 +356,11 @@
       base::CommandLine(base::CommandLine::NO_PROGRAM),
       /*is_quic_force_disabled=*/false, quic_user_agent_id, &params_);
 
-  globals_->system_proxy_resolution_service = ProxyServiceFactory::CreateProxyService(
-      net_log_, nullptr, globals_->system_network_delegate.get(),
-      std::move(system_proxy_config_service_), true /* quick_check_enabled */);
+  globals_->system_proxy_resolution_service =
+      ProxyServiceFactory::CreateProxyResolutionService(
+          net_log_, nullptr, globals_->system_network_delegate.get(),
+          std::move(system_proxy_config_service_),
+          true /* quick_check_enabled */);
 
   globals_->system_request_context.reset(
       ConstructSystemRequestContext(globals_, params_, net_log_));
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index e48bbeb5..2c8da65 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -404,11 +404,6 @@
   }
 
   void OnMetadata(PipelineMetadata metadata) {
-    if (base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)) {
-      EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId())
-          .WillOnce(ReturnRef(frame_sink_id_));
-      EXPECT_CALL(*compositor_, EnableSubmission(_, _));
-    }
     wmpi_->OnMetadata(metadata);
   }
 
@@ -927,6 +922,13 @@
   InitializeWebMediaPlayerImpl();
   PipelineMetadata metadata;
 
+  EXPECT_CALL(client_, SetWebLayer(_)).Times(0);
+
+  if (base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)) {
+    EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()).Times(0);
+    EXPECT_CALL(*compositor_, EnableSubmission(_, _)).Times(0);
+  }
+
   // Nothing should happen.  In particular, no assertions should fail.
   OnMetadata(metadata);
 }
@@ -938,7 +940,15 @@
   metadata.video_decoder_config = TestVideoConfig::Normal();
   metadata.natural_size = gfx::Size(320, 240);
 
-  EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) {
+    EXPECT_CALL(client_, SetWebLayer(_)).Times(0);
+    EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId())
+        .WillOnce(ReturnRef(frame_sink_id_));
+    EXPECT_CALL(*compositor_, EnableSubmission(_, _));
+  } else {
+    EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  }
+
   OnMetadata(metadata);
   ASSERT_EQ(blink::WebSize(320, 240), wmpi_->NaturalSize());
 
@@ -955,7 +965,15 @@
       TestVideoConfig::NormalRotated(VIDEO_ROTATION_90);
   metadata.natural_size = gfx::Size(320, 240);
 
-  EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) {
+    EXPECT_CALL(client_, SetWebLayer(_)).Times(0);
+    EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId())
+        .WillOnce(ReturnRef(frame_sink_id_));
+    EXPECT_CALL(*compositor_, EnableSubmission(_, _));
+  } else {
+    EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  }
+
   OnMetadata(metadata);
   ASSERT_EQ(blink::WebSize(320, 240), wmpi_->NaturalSize());
 
@@ -972,7 +990,16 @@
   PipelineMetadata metadata;
   metadata.has_video = true;
   metadata.video_decoder_config = TestVideoConfig::Normal();
-  EXPECT_CALL(client_, SetWebLayer(NotNull()));
+
+  if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) {
+    EXPECT_CALL(client_, SetWebLayer(_)).Times(0);
+    EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId())
+        .WillOnce(ReturnRef(frame_sink_id_));
+    EXPECT_CALL(*compositor_, EnableSubmission(_, _));
+  } else {
+    EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  }
+
   OnMetadata(metadata);
 
   EXPECT_FALSE(IsVideoLockedWhenPausedWhenHidden());
@@ -1037,7 +1064,16 @@
   metadata.has_audio = true;
   metadata.audio_decoder_config = TestAudioConfig::Normal();
   metadata.natural_size = gfx::Size(400, 400);
-  EXPECT_CALL(client_, SetWebLayer(NotNull()));
+
+  if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) {
+    EXPECT_CALL(client_, SetWebLayer(_)).Times(0);
+    EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId())
+        .WillOnce(ReturnRef(frame_sink_id_));
+    EXPECT_CALL(*compositor_, EnableSubmission(_, _));
+  } else {
+    EXPECT_CALL(client_, SetWebLayer(NotNull()));
+  }
+
   OnMetadata(metadata);
 
   EXPECT_EQ(std::numeric_limits<double>::infinity(), wmpi_->Duration());
@@ -1056,7 +1092,7 @@
 
 TEST_F(WebMediaPlayerImplTest, SetContentsLayerGetsWebLayerFromBridge) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitFromCommandLine("UseSurfaceLayerForVideo", "");
+  feature_list.InitFromCommandLine(kUseSurfaceLayerForVideo.name, "");
 
   InitializeWebMediaPlayerImpl();
 
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index f2495d34..317d8c0 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -398,16 +398,25 @@
     } else if (is_win) {
       enabled_features += [ "is_win" ]
     }
-    action_foreach(parser_target_name) {
+
+    action(parser_target_name) {
       script = mojom_generator_script
       inputs = mojom_generator_sources + jinja2_sources
       sources = invoker.sources
-      outputs = [
-        "{{source_gen_dir}}/{{source_name_part}}.p",
-      ]
+      outputs = []
+      filelist = []
+      foreach(source, invoker.sources) {
+        filename = get_path_info("$source", "name")
+        dirname = get_path_info("$source", "gen_dir")
+        outputs += [ "$dirname/$filename.p" ]
+        filelist += [ rebase_path("$source", root_build_dir) ]
+      }
+
+      response_file_contents = filelist
+
       args = [
         "parse",
-        "{{source}}",
+        "--filelist={{response_file_name}}",
         "-o",
         rebase_path(root_gen_dir, root_build_dir),
         "-d",
@@ -443,20 +452,28 @@
       verify_deps_target_name = "${target_name}__verify_deps"
       verify_deps_target_names += [ ":$verify_deps_target_name" ]
       source_file_name = target_name
-      action_foreach(verify_deps_target_name) {
+
+      action(verify_deps_target_name) {
         script = mojom_generator_script
         inputs = mojom_generator_sources + jinja2_sources
         sources = invoker.sources
         deps = [
           ":$parsed_target_name",
         ]
-        outputs = [
-          "{{source_gen_dir}}/{{source_name_part}}.v",
-        ]
+        outputs = []
+        filelist = []
+        foreach(source, invoker.sources) {
+          filename = get_path_info("$source", "name")
+          dirname = get_path_info("$source", "gen_dir")
+          outputs += [ "$dirname/$filename.v" ]
+          filelist += [ rebase_path("$source", root_build_dir) ]
+        }
+
+        response_file_contents = filelist
 
         args = [
           "verify",
-          "{{source}}",
+          "--filelist={{response_file_name}}",
           "-f",
           rebase_path("$target_gen_dir/$source_file_name.deps_sources_list",
                       root_build_dir),
@@ -476,7 +493,6 @@
     common_generator_args = [
       "--use_bundled_pylibs",
       "generate",
-      "{{source}}",
       "-d",
       rebase_path("//", root_build_dir),
       "-I",
@@ -536,7 +552,7 @@
       }
     }
 
-    action_foreach(generator_cpp_message_ids_target_name) {
+    action(generator_cpp_message_ids_target_name) {
       script = mojom_generator_script
       inputs = mojom_generator_sources + jinja2_sources
       sources = invoker.sources
@@ -544,11 +560,18 @@
         ":$parsed_target_name",
         "//mojo/public/tools/bindings:precompile_templates",
       ]
-      outputs = [
-        "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-message-ids.h",
-      ]
+      outputs = []
       args = common_generator_args
+      filelist = []
+      foreach(source, invoker.sources) {
+        outputs += [ "$target_gen_dir/$source-shared-message-ids.h" ]
+        filelist += [ rebase_path("$source", root_build_dir) ]
+      }
+
+      response_file_contents = filelist
+
       args += [
+        "--filelist={{response_file_name}}",
         "--generate_non_variant_code",
         "--generate_message_ids",
         "-g",
@@ -568,7 +591,7 @@
       "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.h",
     ]
     generator_shared_target_name = "${target_name}_shared__generator"
-    action_foreach(generator_shared_target_name) {
+    action(generator_shared_target_name) {
       script = mojom_generator_script
       inputs = mojom_generator_sources + jinja2_sources
       sources = invoker.sources
@@ -577,9 +600,22 @@
                "//mojo/public/tools/bindings:precompile_templates",
              ] + verify_deps_target_names
 
-      outputs = generator_shared_cpp_outputs
+      outputs = []
       args = common_generator_args
+      filelist = []
+      foreach(source, invoker.sources) {
+        filelist += [ rebase_path("$source", root_build_dir) ]
+        outputs += [
+          "$target_gen_dir/$source-shared-internal.h",
+          "$target_gen_dir/$source-shared.cc",
+          "$target_gen_dir/$source-shared.h",
+        ]
+      }
+
+      response_file_contents = filelist
+
       args += [
+        "--filelist={{response_file_name}}",
         "--generate_non_variant_code",
         "-g",
         "c++",
@@ -742,7 +778,7 @@
       }
 
       generator_target_name = "${target_name}${variant_suffix}__generator"
-      action_foreach(generator_target_name) {
+      action(generator_target_name) {
         script = mojom_generator_script
         inputs = mojom_generator_sources + jinja2_sources
         sources = invoker.sources
@@ -751,9 +787,21 @@
                  ":$type_mappings_target_name",
                  "//mojo/public/tools/bindings:precompile_templates",
                ] + verify_deps_target_names
-        outputs = generator_cpp_outputs
+        outputs = []
         args = common_generator_args
+        filelist = []
+        foreach(source, invoker.sources) {
+          filelist += [ rebase_path("$source", root_build_dir) ]
+          outputs += [
+            "$target_gen_dir/${source}${variant_dash_suffix}.cc",
+            "$target_gen_dir/${source}${variant_dash_suffix}.h",
+          ]
+        }
+
+        response_file_contents = filelist
+
         args += [
+          "--filelist={{response_file_name}}",
           "-g",
           "c++",
         ]
@@ -994,7 +1042,7 @@
       if (enabled_sources != []) {
         generator_java_outputs =
             [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
-        action_foreach(java_generator_target_name) {
+        action(java_generator_target_name) {
           script = mojom_generator_script
           inputs = mojom_generator_sources + jinja2_sources
           sources = enabled_sources
@@ -1003,9 +1051,18 @@
                    ":$type_mappings_target_name",
                    "//mojo/public/tools/bindings:precompile_templates",
                  ] + verify_deps_target_names
-          outputs = generator_java_outputs
+          outputs = []
           args = common_generator_args
+          filelist = []
+          foreach(source, invoker.sources) {
+            filelist += [ rebase_path("$source", root_build_dir) ]
+            outputs += [ "$target_gen_dir/$source.srcjar" ]
+          }
+
+          response_file_contents = filelist
+
           args += [
+            "--filelist={{response_file_name}}",
             "-g",
             "java",
           ]
@@ -1078,7 +1135,7 @@
         "{{source_gen_dir}}/{{source_name_part}}.mojom.js",
         "{{source_gen_dir}}/{{source_name_part}}.mojom.externs.js",
       ]
-      action_foreach(generator_js_target_name) {
+      action(generator_js_target_name) {
         script = mojom_generator_script
         inputs = mojom_generator_sources + jinja2_sources
         sources = []
@@ -1089,9 +1146,21 @@
                  ":$parsed_target_name",
                  "//mojo/public/tools/bindings:precompile_templates",
                ] + verify_deps_target_names
-        outputs = generator_js_outputs
+        outputs = []
         args = common_generator_args
+        filelist = []
+        foreach(source, invoker.sources) {
+          filelist += [ rebase_path("$source", root_build_dir) ]
+          outputs += [
+            "$target_gen_dir/$source.js",
+            "$target_gen_dir/$source.externs.js",
+          ]
+        }
+
+        response_file_contents = filelist
+
         args += [
+          "--filelist={{response_file_name}}",
           "-g",
           "javascript",
         ]
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
index 7b0d3da..4117629 100755
--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -243,6 +243,11 @@
 
   processor = MojomProcessor(lambda filename: filename in args.filename)
   processor.LoadTypemaps(set(args.typemaps))
+
+  if args.filelist:
+    with open(args.filelist) as f:
+      args.filename.extend(f.read().split())
+
   for filename in args.filename:
     processor._GenerateModule(args, remaining_args, generator_modules,
                               RelativePath(filename, args.depth), [])
@@ -293,6 +298,11 @@
 
 def _Parse(args, _):
   fileutil.EnsureDirectoryExists(args.output_dir)
+
+  if args.filelist:
+    with open(args.filelist) as f:
+      args.filename.extend(f.read().split())
+
   for filename in args.filename:
     _ParseFile(args, RelativePath(filename, args.depth))
   return 0
@@ -307,6 +317,10 @@
 def _VerifyImportDeps(args, __):
   fileutil.EnsureDirectoryExists(args.gen_dir)
 
+  if args.filelist:
+    with open(args.filelist) as f:
+      args.filename.extend(f.read().split())
+
   for filename in args.filename:
     rel_path = RelativePath(filename, args.depth)
     tree = _UnpickleAST(_GetPicklePath(rel_path, args.gen_dir))
@@ -352,7 +366,8 @@
   parse_parser = subparsers.add_parser(
       "parse", description="Parse mojom to AST and remove disabled definitions."
                            " Pickle pruned AST into output_dir.")
-  parse_parser.add_argument("filename", nargs="+", help="mojom input file")
+  parse_parser.add_argument("filename", nargs="*", help="mojom input file")
+  parse_parser.add_argument("--filelist", help="mojom input file list")
   parse_parser.add_argument(
       "-o",
       "--output_dir",
@@ -373,8 +388,9 @@
 
   generate_parser = subparsers.add_parser(
       "generate", description="Generate bindings from mojom files.")
-  generate_parser.add_argument("filename", nargs="+",
+  generate_parser.add_argument("filename", nargs="*",
                                help="mojom input file")
+  generate_parser.add_argument("--filelist", help="mojom input file list")
   generate_parser.add_argument("-d", "--depth", dest="depth", default=".",
                                help="depth from source root")
   generate_parser.add_argument("-o", "--output_dir", dest="output_dir",
@@ -461,8 +477,9 @@
 
   verify_parser = subparsers.add_parser("verify", description="Checks "
       "the set of imports against the set of dependencies.")
-  verify_parser.add_argument("filename", nargs="+",
+  verify_parser.add_argument("filename", nargs="*",
       help="mojom input file")
+  verify_parser.add_argument("--filelist", help="mojom input file list")
   verify_parser.add_argument("-f", "--file", dest="deps_file",
       help="file containing paths to the sources files for "
       "dependencies")
diff --git a/net/android/keystore.cc b/net/android/keystore.cc
index 2115730..8104682e 100644
--- a/net/android/keystore.cc
+++ b/net/android/keystore.cc
@@ -35,7 +35,7 @@
 
   // Convert message to byte[] array.
   ScopedJavaLocalRef<jbyteArray> input_ref =
-      ToJavaByteArray(env, input.data(), input.length());
+      ToJavaByteArray(env, input.data(), input.size());
   DCHECK(!input_ref.is_null());
 
   // Invoke platform API
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index 4012beb..b5c698f 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -49,6 +49,18 @@
   COOKIE_LOAD_PROBLEM_LAST_ENTRY
 };
 
+// Used to populate a histogram for problems when committing cookies.
+//
+// Please do not reorder or remove entries. New entries must be added to the
+// end of the list, just before COOKIE_COMMIT_PROBLEM_LAST_ENTRY.
+enum CookieCommitProblem {
+  COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED = 0,
+  COOKIE_COMMIT_PROBLEM_ADD = 1,
+  COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS = 2,
+  COOKIE_COMMIT_PROBLEM_DELETE = 3,
+  COOKIE_COMMIT_PROBLEM_LAST_ENTRY
+};
+
 // Used to report a histogram on status of cookie commit to disk.
 //
 // Please do not reorder or remove entries. New entries must be added to the
@@ -56,13 +68,19 @@
 enum BackingStoreResults {
   BACKING_STORE_RESULTS_SUCCESS = 0,
   BACKING_STORE_RESULTS_FAILURE = 1,
+  BACKING_STORE_RESULTS_MIXED = 2,
   BACKING_STORE_RESULTS_LAST_ENTRY
 };
 
 void RecordCookieLoadProblem(CookieLoadProblem event) {
   UMA_HISTOGRAM_ENUMERATION("Cookie.LoadProblem", event,
                             COOKIE_LOAD_PROBLEM_LAST_ENTRY);
-};
+}
+
+void RecordCookieCommitProblem(CookieCommitProblem event) {
+  UMA_HISTOGRAM_ENUMERATION("Cookie.CommitProblem", event,
+                            COOKIE_COMMIT_PROBLEM_LAST_ENTRY);
+}
 
 // The persistent cookie store is loaded into memory on eTLD at a time. This
 // variable controls the delay between loading eTLDs, so as to not overload the
@@ -1274,6 +1292,7 @@
   if (!transaction.Begin())
     return;
 
+  bool trouble = false;
   for (PendingOperationsList::iterator it = ops.begin(); it != ops.end();
        ++it) {
     // Free the cookies as we commit them to the database.
@@ -1286,8 +1305,12 @@
         add_smt.BindString(2, po->cc().Name());
         if (crypto_ && crypto_->ShouldEncrypt()) {
           std::string encrypted_value;
-          if (!crypto_->EncryptString(po->cc().Value(), &encrypted_value))
+          if (!crypto_->EncryptString(po->cc().Value(), &encrypted_value)) {
+            DLOG(WARNING) << "Could not encrypt a cookie, skipping add.";
+            RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED);
+            trouble = true;
             continue;
+          }
           add_smt.BindCString(3, "");  // value
           // BindBlob() immediately makes an internal copy of the data.
           add_smt.BindBlob(4, encrypted_value.data(),
@@ -1307,8 +1330,11 @@
         add_smt.BindInt(12, po->cc().IsPersistent());
         add_smt.BindInt(13,
                         CookiePriorityToDBCookiePriority(po->cc().Priority()));
-        if (!add_smt.Run())
-          NOTREACHED() << "Could not add a cookie to the DB.";
+        if (!add_smt.Run()) {
+          DLOG(WARNING) << "Could not add a cookie to the DB.";
+          RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ADD);
+          trouble = true;
+        }
         break;
 
       case PendingOperation::COOKIE_UPDATEACCESS:
@@ -1318,8 +1344,12 @@
         update_access_smt.BindString(1, po->cc().Name());
         update_access_smt.BindString(2, po->cc().Domain());
         update_access_smt.BindString(3, po->cc().Path());
-        if (!update_access_smt.Run())
-          NOTREACHED() << "Could not update cookie last access time in the DB.";
+        if (!update_access_smt.Run()) {
+          DLOG(WARNING)
+              << "Could not update cookie last access time in the DB.";
+          RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS);
+          trouble = true;
+        }
         break;
 
       case PendingOperation::COOKIE_DELETE:
@@ -1327,8 +1357,11 @@
         del_smt.BindString(0, po->cc().Name());
         del_smt.BindString(1, po->cc().Domain());
         del_smt.BindString(2, po->cc().Path());
-        if (!del_smt.Run())
-          NOTREACHED() << "Could not delete a cookie from the DB.";
+        if (!del_smt.Run()) {
+          DLOG(WARNING) << "Could not delete a cookie from the DB.";
+          RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_DELETE);
+          trouble = true;
+        }
         break;
 
       default:
@@ -1337,10 +1370,12 @@
     }
   }
   bool succeeded = transaction.Commit();
-  UMA_HISTOGRAM_ENUMERATION(
-      "Cookie.BackingStoreUpdateResults",
-      succeeded ? BACKING_STORE_RESULTS_SUCCESS : BACKING_STORE_RESULTS_FAILURE,
-      BACKING_STORE_RESULTS_LAST_ENTRY);
+  UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults",
+                            succeeded
+                                ? (trouble ? BACKING_STORE_RESULTS_MIXED
+                                           : BACKING_STORE_RESULTS_SUCCESS)
+                                : BACKING_STORE_RESULTS_FAILURE,
+                            BACKING_STORE_RESULTS_LAST_ENTRY);
 }
 
 void SQLitePersistentCookieStore::Backend::SetBeforeFlushCallback(
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 0041907..ebdc8dc 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -189,11 +189,11 @@
   // not changed. This method returns without blocking, and the operation will
   // be performed asynchronously without any completion notification.
   // Takes ownership of |buf|.
-  void WriteMetadata(const GURL& url,
-                     RequestPriority priority,
-                     base::Time expected_response_time,
-                     IOBuffer* buf,
-                     int buf_len);
+  virtual void WriteMetadata(const GURL& url,
+                             RequestPriority priority,
+                             base::Time expected_response_time,
+                             IOBuffer* buf,
+                             int buf_len);
 
   // Get/Set the cache's mode.
   void set_mode(Mode value) { mode_ = value; }
diff --git a/net/proxy_resolution/proxy_resolution_service.cc b/net/proxy_resolution/proxy_resolution_service.cc
index 241dd4b..c48f04e 100644
--- a/net/proxy_resolution/proxy_resolution_service.cc
+++ b/net/proxy_resolution/proxy_resolution_service.cc
@@ -728,9 +728,10 @@
       // the notification.
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
-          base::Bind(&PacFileDeciderPoller::NotifyProxyServiceOfChange,
-                     weak_factory_.GetWeakPtr(), result,
-                     decider_->script_data(), decider_->effective_config()));
+          base::Bind(
+              &PacFileDeciderPoller::NotifyProxyResolutionServiceOfChange,
+              weak_factory_.GetWeakPtr(), result, decider_->script_data(),
+              decider_->effective_config()));
       return;
     }
 
@@ -764,7 +765,7 @@
     return !script_data->Equals(last_script_data_.get());
   }
 
-  void NotifyProxyServiceOfChange(
+  void NotifyProxyResolutionServiceOfChange(
       int result,
       const scoped_refptr<PacFileData>& script_data,
       const ProxyConfigWithAnnotation& effective_config) {
diff --git a/net/proxy_resolution/proxy_resolution_service.h b/net/proxy_resolution/proxy_resolution_service.h
index e438c6a..de6bd2a9 100644
--- a/net/proxy_resolution/proxy_resolution_service.h
+++ b/net/proxy_resolution/proxy_resolution_service.h
@@ -236,9 +236,9 @@
   // to downloading and testing the PAC files.
   void ForceReloadProxyConfig();
 
-  // Same as CreateProxyServiceUsingV8ProxyResolver, except it uses system
-  // libraries for evaluating the PAC script if available, otherwise skips
-  // proxy autoconfig.
+  // Same as CreateProxyResolutionServiceUsingV8ProxyResolver, except it uses
+  // system libraries for evaluating the PAC script if available, otherwise
+  // skips proxy autoconfig.
   static std::unique_ptr<ProxyResolutionService> CreateUsingSystemProxyResolver(
       std::unique_ptr<ProxyConfigService> proxy_config_service,
       NetLog* net_log);
@@ -304,8 +304,10 @@
   }
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigAfterFailedAutodetect);
-  FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigFromPACToDirect);
+  FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
+                           UpdateConfigAfterFailedAutodetect);
+  FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
+                           UpdateConfigFromPACToDirect);
   friend class Request;
   class InitProxyResolver;
   class PacFileDeciderPoller;
diff --git a/net/proxy_resolution/proxy_resolution_service_unittest.cc b/net/proxy_resolution/proxy_resolution_service_unittest.cc
index 62750fe0..7a417a8 100644
--- a/net/proxy_resolution/proxy_resolution_service_unittest.cc
+++ b/net/proxy_resolution/proxy_resolution_service_unittest.cc
@@ -114,7 +114,7 @@
 //
 // The tests which verify the polling code re-enable the polling behavior but
 // are careful to avoid timing problems.
-class ProxyServiceTest : public testing::Test {
+class ProxyResolutionServiceTest : public testing::Test {
  protected:
   void SetUp() override {
     testing::Test::SetUp();
@@ -334,7 +334,7 @@
 
 }  // namespace
 
-TEST_F(ProxyServiceTest, Direct) {
+TEST_F(ProxyResolutionServiceTest, Direct) {
   MockAsyncProxyResolverFactory* factory =
       new MockAsyncProxyResolverFactory(false);
   ProxyResolutionService service(
@@ -369,7 +369,7 @@
                                   NetLogEventType::PROXY_RESOLUTION_SERVICE));
 }
 
-TEST_F(ProxyServiceTest, OnResolveProxyCallbackAddProxy) {
+TEST_F(ProxyResolutionServiceTest, OnResolveProxyCallbackAddProxy) {
   ProxyConfig config;
   config.proxy_rules().ParseFromString("badproxy:8080,foopy1:8080");
   config.set_auto_detect(false);
@@ -429,7 +429,7 @@
   EXPECT_TRUE(info.is_direct());
 }
 
-TEST_F(ProxyServiceTest, OnResolveProxyCallbackRemoveProxy) {
+TEST_F(ProxyResolutionServiceTest, OnResolveProxyCallbackRemoveProxy) {
   // Same as OnResolveProxyCallbackAddProxy, but verify that the
   // ProxyDelegate's behavior is stateless across invocations after it
   // *removes* a proxy.
@@ -474,7 +474,7 @@
   EXPECT_TRUE(info.is_direct());
 }
 
-TEST_F(ProxyServiceTest, PAC) {
+TEST_F(ProxyResolutionServiceTest, PAC) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -538,7 +538,7 @@
 
 // Test that the proxy resolver does not see the URL's username/password
 // or its reference section.
-TEST_F(ProxyServiceTest, PAC_NoIdentityOrHash) {
+TEST_F(ProxyResolutionServiceTest, PAC_NoIdentityOrHash) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -570,7 +570,7 @@
   // ProxyResolutionService will cancel the outstanding request.
 }
 
-TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
+TEST_F(ProxyResolutionServiceTest, PAC_FailoverWithoutDirect) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
   MockAsyncProxyResolver resolver;
@@ -617,7 +617,7 @@
 
 // Test that if the execution of the PAC script fails (i.e. javascript runtime
 // error), and the PAC settings are non-mandatory, that we fall-back to direct.
-TEST_F(ProxyServiceTest, PAC_RuntimeError) {
+TEST_F(ProxyResolutionServiceTest, PAC_RuntimeError) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
   MockAsyncProxyResolver resolver;
@@ -674,7 +674,7 @@
 //
 // The important check of this test is to make sure that DIRECT is not somehow
 // cached as being a bad proxy.
-TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
+TEST_F(ProxyResolutionServiceTest, PAC_FailoverAfterDirect) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
   MockAsyncProxyResolver resolver;
@@ -726,7 +726,7 @@
   EXPECT_TRUE(info.is_empty());
 }
 
-TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) {
+TEST_F(ProxyResolutionServiceTest, PAC_ConfigSourcePropagates) {
   // Test whether the ProxyConfigSource set by the ProxyConfigService is applied
   // to ProxyInfo after the proxy is resolved via a PAC script.
   ProxyConfig config =
@@ -763,7 +763,7 @@
   EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
 }
 
-TEST_F(ProxyServiceTest, ProxyResolverFails) {
+TEST_F(ProxyResolutionServiceTest, ProxyResolverFails) {
   // Test what happens when the ProxyResolver fails. The download and setting
   // of the PAC script have already succeeded, so this corresponds with a
   // javascript runtime error while calling FindProxyForURL().
@@ -826,7 +826,7 @@
   EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
 }
 
-TEST_F(ProxyServiceTest, ProxyResolverTerminatedDuringRequest) {
+TEST_F(ProxyResolutionServiceTest, ProxyResolverTerminatedDuringRequest) {
   // Test what happens when the ProxyResolver fails with a fatal error while
   // a GetProxyForURL() call is in progress.
 
@@ -895,7 +895,7 @@
   EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
 }
 
-TEST_F(ProxyServiceTest,
+TEST_F(ProxyResolutionServiceTest,
        ProxyResolverTerminatedDuringRequestWithConcurrentRequest) {
   // Test what happens when the ProxyResolver fails with a fatal error while
   // a GetProxyForURL() call is in progress.
@@ -965,7 +965,7 @@
   EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
 }
 
-TEST_F(ProxyServiceTest, PacFileFetcherFailsDownloadingMandatoryPac) {
+TEST_F(ProxyResolutionServiceTest, PacFileFetcherFailsDownloadingMandatoryPac) {
   // Test what happens when the ProxyResolver fails to download a mandatory PAC
   // script.
 
@@ -1011,7 +1011,8 @@
   EXPECT_FALSE(info.is_direct());
 }
 
-TEST_F(ProxyServiceTest, ProxyResolverFailsParsingJavaScriptMandatoryPac) {
+TEST_F(ProxyResolutionServiceTest,
+       ProxyResolverFailsParsingJavaScriptMandatoryPac) {
   // Test what happens when the ProxyResolver fails that is configured to use a
   // mandatory PAC script. The download of the PAC script has already
   // succeeded but the PAC script contains no valid javascript.
@@ -1059,7 +1060,7 @@
   EXPECT_FALSE(info.is_direct());
 }
 
-TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
+TEST_F(ProxyResolutionServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
   // Test what happens when the ProxyResolver fails that is configured to use a
   // mandatory PAC script. The download and setting of the PAC script have
   // already succeeded, so this corresponds with a javascript runtime error
@@ -1122,7 +1123,7 @@
   EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
 }
 
-TEST_F(ProxyServiceTest, ProxyFallback) {
+TEST_F(ProxyResolutionServiceTest, ProxyFallback) {
   // Test what happens when we specify multiple proxy servers and some of them
   // are bad.
 
@@ -1259,7 +1260,7 @@
 
 // This test is similar to ProxyFallback, but this time we have an explicit
 // fallback choice to DIRECT.
-TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
+TEST_F(ProxyResolutionServiceTest, ProxyFallbackToDirect) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -1318,7 +1319,7 @@
   EXPECT_FALSE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
 }
 
-TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
+TEST_F(ProxyResolutionServiceTest, ProxyFallback_BadConfig) {
   // Test proxy failover when the configuration is bad.
 
   MockProxyConfigService* config_service =
@@ -1413,7 +1414,7 @@
   EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
 }
 
-TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
+TEST_F(ProxyResolutionServiceTest, ProxyFallback_BadConfigMandatory) {
   // Test proxy failover when the configuration is bad.
 
   ProxyConfig config(
@@ -1508,7 +1509,7 @@
   EXPECT_EQ(2u, info3.proxy_list().size());
 }
 
-TEST_F(ProxyServiceTest, ProxyBypassList) {
+TEST_F(ProxyResolutionServiceTest, ProxyBypassList) {
   // Test that the proxy bypass rules are consulted.
 
   TestCompletionCallback callback[2];
@@ -1540,7 +1541,7 @@
   EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI());
 }
 
-TEST_F(ProxyServiceTest, MarkProxiesAsBadTests) {
+TEST_F(ProxyResolutionServiceTest, MarkProxiesAsBadTests) {
   ProxyConfig config;
   config.proxy_rules().ParseFromString(
       "http=foopy1:8080;http=foopy2:8080;http=foopy3.8080;http=foopy4:8080");
@@ -1575,7 +1576,7 @@
   }
 }
 
-TEST_F(ProxyServiceTest, PerProtocolProxyTests) {
+TEST_F(ProxyResolutionServiceTest, PerProtocolProxyTests) {
   ProxyConfig config;
   config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
   config.set_auto_detect(false);
@@ -1634,7 +1635,7 @@
   }
 }
 
-TEST_F(ProxyServiceTest, ProxyConfigTrafficAnnotationPropagates) {
+TEST_F(ProxyResolutionServiceTest, ProxyConfigTrafficAnnotationPropagates) {
   // Test that the proxy config source is set correctly when resolving proxies
   // using manual proxy rules. Namely, the config source should only be set if
   // any of the rules were applied.
@@ -1689,7 +1690,7 @@
 
 // If only HTTP and a SOCKS proxy are specified, check if ftp/https queries
 // fall back to the SOCKS proxy.
-TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
+TEST_F(ProxyResolutionServiceTest, DefaultProxyFallbackToSOCKS) {
   ProxyConfig config;
   config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080");
   config.set_auto_detect(false);
@@ -1751,7 +1752,7 @@
 }
 
 // Test cancellation of an in-progress request.
-TEST_F(ProxyServiceTest, CancelInProgressRequest) {
+TEST_F(ProxyResolutionServiceTest, CancelInProgressRequest) {
   const GURL url1("http://request1");
   const GURL url2("http://request2");
   const GURL url3("http://request3");
@@ -1821,7 +1822,7 @@
 }
 
 // Test the initial PAC download for resolver that expects bytes.
-TEST_F(ProxyServiceTest, InitialPACScriptDownload) {
+TEST_F(ProxyResolutionServiceTest, InitialPACScriptDownload) {
   const GURL url1("http://request1");
   const GURL url2("http://request2");
   const GURL url3("http://request3");
@@ -1926,7 +1927,8 @@
 }
 
 // Test changing the PacFileFetcher while PAC download is in progress.
-TEST_F(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
+TEST_F(ProxyResolutionServiceTest,
+       ChangeScriptFetcherWhilePACDownloadInProgress) {
   const GURL url1("http://request1");
   const GURL url2("http://request2");
   MockProxyConfigService* config_service =
@@ -1988,7 +1990,7 @@
 }
 
 // Test cancellation of a request, while the PAC script is being fetched.
-TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
+TEST_F(ProxyResolutionServiceTest, CancelWhilePACFetching) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -2084,7 +2086,7 @@
 }
 
 // Test that if auto-detect fails, we fall-back to the custom pac.
-TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
+TEST_F(ProxyResolutionServiceTest, FallbackFromAutodetectToCustomPac) {
   const GURL url1("http://request1");
   const GURL url2("http://request2");
   ProxyConfig config;
@@ -2167,7 +2169,7 @@
 
 // This is the same test as FallbackFromAutodetectToCustomPac, except
 // the auto-detect script fails parsing rather than downloading.
-TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
+TEST_F(ProxyResolutionServiceTest, FallbackFromAutodetectToCustomPac2) {
   const GURL url1("http://request1");
   const GURL url2("http://request2");
   ProxyConfig config;
@@ -2246,7 +2248,7 @@
 
 // Test that if all of auto-detect, a custom PAC script, and manual settings
 // are given, then we will try them in that order.
-TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
+TEST_F(ProxyResolutionServiceTest, FallbackFromAutodetectToCustomToManual) {
   ProxyConfig config;
   config.set_auto_detect(true);
   config.set_pac_url(GURL("http://foopy/proxy.pac"));
@@ -2306,7 +2308,7 @@
 }
 
 // Test that the bypass rules are NOT applied when using autodetect.
-TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) {
+TEST_F(ProxyResolutionServiceTest, BypassDoesntApplyToPac) {
   ProxyConfig config;
   config.set_auto_detect(true);
   config.set_pac_url(GURL("http://foopy/proxy.pac"));
@@ -2379,7 +2381,8 @@
 // request to the script fetcher. When run under valgrind, should not
 // have any memory errors (used to be that the PacFileFetcher was
 // being deleted prior to the InitProxyResolver).
-TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
+TEST_F(ProxyResolutionServiceTest,
+       DeleteWhileInitProxyResolverHasOutstandingFetch) {
   ProxyConfig config =
     ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
 
@@ -2415,7 +2418,8 @@
 // request to the proxy resolver. When run under valgrind, should not
 // have any memory errors (used to be that the ProxyResolver was
 // being deleted prior to the InitProxyResolver).
-TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) {
+TEST_F(ProxyResolutionServiceTest,
+       DeleteWhileInitProxyResolverHasOutstandingSet) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -2437,7 +2441,7 @@
             factory->pending_requests()[0]->script_data()->url());
 }
 
-TEST_F(ProxyServiceTest, ResetProxyConfigService) {
+TEST_F(ProxyResolutionServiceTest, ResetProxyConfigService) {
   ProxyConfig config1;
   config1.proxy_rules().ParseFromString("foopy1:8080");
   config1.set_auto_detect(false);
@@ -2466,7 +2470,7 @@
 
 // Test that when going from a configuration that required PAC to one
 // that does NOT, we unset the variable |should_use_proxy_resolver_|.
-TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) {
+TEST_F(ProxyResolutionServiceTest, UpdateConfigFromPACToDirect) {
   ProxyConfig config = ProxyConfig::CreateAutoDetect();
 
   MockProxyConfigService* config_service = new MockProxyConfigService(config);
@@ -2517,7 +2521,7 @@
   EXPECT_TRUE(info2.is_direct());
 }
 
-TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
+TEST_F(ProxyResolutionServiceTest, NetworkChangeTriggersPacRefetch) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -2636,7 +2640,7 @@
 // periodically polled for changes. Specifically, if the initial fetch fails due
 // to a network error, we will eventually re-configure the service to use the
 // script once it becomes available.
-TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
+TEST_F(ProxyResolutionServiceTest, PACScriptRefetchAfterFailure) {
   // Change the retry policy to wait a mere 1 ms before retrying, so the test
   // runs quickly.
   ImmediatePollPolicy poll_policy;
@@ -2743,7 +2747,7 @@
 // periodically polled for changes. Specifically, if the initial fetch succeeds,
 // however at a later time its *contents* change, we will eventually
 // re-configure the service to use the new script.
-TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
+TEST_F(ProxyResolutionServiceTest, PACScriptRefetchAfterContentChange) {
   // Change the retry policy to wait a mere 1 ms before retrying, so the test
   // runs quickly.
   ImmediatePollPolicy poll_policy;
@@ -2856,7 +2860,7 @@
 // periodically polled for changes. Specifically, if the initial fetch succeeds
 // and so does the next poll, however the contents of the downloaded script
 // have NOT changed, then we do not bother to re-initialize the proxy resolver.
-TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
+TEST_F(ProxyResolutionServiceTest, PACScriptRefetchAfterContentUnchanged) {
   // Change the retry policy to wait a mere 1 ms before retrying, so the test
   // runs quickly.
   ImmediatePollPolicy poll_policy;
@@ -2966,7 +2970,7 @@
 // periodically polled for changes. Specifically, if the initial fetch succeeds,
 // however at a later time it starts to fail, we should re-configure the
 // ProxyResolutionService to stop using that PAC script.
-TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
+TEST_F(ProxyResolutionServiceTest, PACScriptRefetchAfterSuccess) {
   // Change the retry policy to wait a mere 1 ms before retrying, so the test
   // runs quickly.
   ImmediatePollPolicy poll_policy;
@@ -3060,7 +3064,7 @@
 
 // Tests that the code which decides at what times to poll the PAC
 // script follows the expected policy.
-TEST_F(ProxyServiceTest, PACScriptPollingPolicy) {
+TEST_F(ProxyResolutionServiceTest, PACScriptPollingPolicy) {
   // Retrieve the internal polling policy implementation used by
   // ProxyResolutionService.
   std::unique_ptr<ProxyResolutionService::PacPollPolicy> policy =
@@ -3131,7 +3135,7 @@
 
 // This tests the polling of the PAC script. Specifically, it tests that
 // polling occurs in response to user activity.
-TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
+TEST_F(ProxyResolutionServiceTest, PACScriptRefetchAfterActivity) {
   ImmediateAfterActivityPollPolicy poll_policy;
   ProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
 
@@ -3237,7 +3241,7 @@
 }
 
 // Test that the synchronous resolution fails when a PAC script is active.
-TEST_F(ProxyServiceTest, SynchronousWithPAC) {
+TEST_F(ProxyResolutionServiceTest, SynchronousWithPAC) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -3263,7 +3267,7 @@
 
 // Test that synchronous results are returned correctly if a fixed proxy
 // configuration is active.
-TEST_F(ProxyServiceTest, SynchronousWithFixedConfiguration) {
+TEST_F(ProxyResolutionServiceTest, SynchronousWithFixedConfiguration) {
   ProxyConfig config;
   config.proxy_rules().ParseFromString("foopy1:8080");
   config.set_auto_detect(false);
@@ -3375,7 +3379,7 @@
   std::unique_ptr<ProxyResolutionService> service_;
 };
 
-TEST_F(ProxyServiceTest, SanitizeUrlDefaultsToSafe) {
+TEST_F(ProxyResolutionServiceTest, SanitizeUrlDefaultsToSafe) {
   SanitizeUrlHelper helper;
 
   // Without changing the URL sanitization policy, the default should be to
@@ -3388,7 +3392,7 @@
 // Tests URL sanitization with input URLs that have a // non-cryptographic
 // scheme (i.e. http://). The sanitized result is consistent regardless of the
 // stripping mode selected.
-TEST_F(ProxyServiceTest, SanitizeUrlForPacScriptNonCryptographic) {
+TEST_F(ProxyResolutionServiceTest, SanitizeUrlForPacScriptNonCryptographic) {
   const struct {
     const char* raw_url;
     const char* sanitized_url;
@@ -3447,7 +3451,7 @@
 // Tests URL sanitization using input URLs that have a cryptographic schemes
 // (i.e. https://). The sanitized result differs depending on the sanitization
 // mode chosen.
-TEST_F(ProxyServiceTest, SanitizeUrlForPacScriptCryptographic) {
+TEST_F(ProxyResolutionServiceTest, SanitizeUrlForPacScriptCryptographic) {
   const struct {
     // Input URL.
     const char* raw_url;
@@ -3510,7 +3514,7 @@
   }
 }
 
-TEST_F(ProxyServiceTest, OnShutdownWithLiveRequest) {
+TEST_F(ProxyResolutionServiceTest, OnShutdownWithLiveRequest) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
@@ -3543,7 +3547,7 @@
   EXPECT_TRUE(info.is_direct());
 }
 
-TEST_F(ProxyServiceTest, OnShutdownFollowedByRequest) {
+TEST_F(ProxyResolutionServiceTest, OnShutdownFollowedByRequest) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
 
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index c86c7fe..c975edc 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -516,10 +516,10 @@
               base::ThreadTaskRunnerHandle::Get().get());
     }
 #endif  // !defined(OS_LINUX) && !defined(OS_ANDROID)
-    proxy_resolution_service_ =
-        CreateProxyService(std::move(proxy_config_service_), context.get(),
-                           context->host_resolver(),
-                           context->network_delegate(), context->net_log());
+    proxy_resolution_service_ = CreateProxyResolutionService(
+        std::move(proxy_config_service_), context.get(),
+        context->host_resolver(), context->network_delegate(),
+        context->net_log());
     proxy_resolution_service_->set_quick_check_enabled(pac_quick_check_enabled_);
     proxy_resolution_service_->set_sanitize_url_policy(pac_sanitize_url_policy_);
   }
@@ -659,7 +659,7 @@
 }
 
 std::unique_ptr<ProxyResolutionService>
-URLRequestContextBuilder::CreateProxyService(
+URLRequestContextBuilder::CreateProxyResolutionService(
     std::unique_ptr<ProxyConfigService> proxy_config_service,
     URLRequestContext* url_request_context,
     HostResolver* host_resolver,
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 690a9ed..66255620 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -166,8 +166,8 @@
 
   // Sets the proxy service. If one is not provided, by default, uses system
   // libraries to evaluate PAC scripts, if available (And if not, skips PAC
-  // resolution). Subclasses may override CreateProxyService for different
-  // default behavior.
+  // resolution). Subclasses may override CreateProxyResolutionService for
+  // different default behavior.
   void set_proxy_resolution_service(
       std::unique_ptr<ProxyResolutionService> proxy_resolution_service) {
     proxy_resolution_service_ = std::move(proxy_resolution_service);
@@ -348,7 +348,7 @@
   // ProxyResolutionService that uses the URLRequestContext itself to get PAC
   // scripts. When this method is invoked, the URLRequestContext is not yet
   // ready to service requests.
-  virtual std::unique_ptr<ProxyResolutionService> CreateProxyService(
+  virtual std::unique_ptr<ProxyResolutionService> CreateProxyResolutionService(
       std::unique_ptr<ProxyConfigService> proxy_config_service,
       URLRequestContext* url_request_context,
       HostResolver* host_resolver,
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc
index d9c5d80..0ac9793 100644
--- a/net/websockets/websocket_stream_test.cc
+++ b/net/websockets/websocket_stream_test.cc
@@ -20,6 +20,7 @@
 #include "base/timer/mock_timer.h"
 #include "base/timer/timer.h"
 #include "net/base/net_errors.h"
+#include "net/base/url_util.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
@@ -79,11 +80,13 @@
       : MockTimer(retain_user_task, is_repeating) {}
 };
 
+const char kOrigin[] = "http://www.example.org";
+
 static url::Origin Origin() {
-  return url::Origin::Create(GURL("http://www.example.org/"));
+  return url::Origin::Create(GURL(kOrigin));
 }
 
-static GURL Url() {
+static GURL SiteForCookies() {
   return GURL("http://www.example.org/foobar");
 }
 
@@ -131,26 +134,26 @@
   // Set up mock data and start websockets request, either for WebSocket
   // upgraded from an HTTP/1 connection, or for a WebSocket request over HTTP/2.
   void CreateAndConnectStandard(
-      const std::string& socket_url,
-      const std::string& socket_host,
-      const std::string& socket_path,
+      base::StringPiece url,
       const std::vector<std::string>& sub_protocols,
-      const url::Origin& origin,
-      const GURL& site_for_cookies,
       const WebSocketExtraHeaders& send_additional_request_headers,
       const WebSocketExtraHeaders& extra_request_headers,
       const WebSocketExtraHeaders& extra_response_headers) {
+    const GURL socket_url(url);
+    const std::string socket_host = GetHostAndOptionalPort(socket_url);
+    const std::string socket_path = socket_url.path();
+
     if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
       url_request_context_host_.SetExpectations(
           WebSocketStandardRequest(
-              socket_path, socket_host, origin,
+              socket_path, socket_host, Origin(),
               WebSocketExtraHeadersToString(send_additional_request_headers),
               WebSocketExtraHeadersToString(extra_request_headers)),
           WebSocketStandardResponse(
               WebSocketExtraHeadersToString(extra_response_headers)) +
               additional_data_);
       CreateAndConnectStream(
-          GURL(socket_url), sub_protocols, origin, site_for_cookies,
+          socket_url, sub_protocols, Origin(), SiteForCookies(),
           WebSocketExtraHeadersToString(send_additional_request_headers),
           std::move(timer_));
       return;
@@ -219,9 +222,8 @@
     spdy_util_.UpdateWithStreamDestruction(1);
 
     // WebSocket request.
-    SpdyHeaderBlock request_headers =
-        WebSocketHttp2Request(socket_path, "www.example.org",
-                              "http://www.example.org", extra_request_headers);
+    SpdyHeaderBlock request_headers = WebSocketHttp2Request(
+        socket_path, socket_host, kOrigin, extra_request_headers);
     frames_.push_back(spdy_util_.ConstructSpdyHeaders(
         3, std::move(request_headers), DEFAULT_PRIORITY, false));
     AddWrite(&frames_.back());
@@ -284,7 +286,7 @@
     EXPECT_FALSE(request->is_pending());
 
     CreateAndConnectStream(
-        GURL(socket_url), sub_protocols, origin, site_for_cookies,
+        socket_url, sub_protocols, Origin(), SiteForCookies(),
         WebSocketExtraHeadersToString(send_additional_request_headers),
         std::move(timer_));
   }
@@ -292,25 +294,25 @@
   // Like CreateAndConnectStandard(), but allow for arbitrary response body.
   // Only for HTTP/1-based WebSockets.
   void CreateAndConnectCustomResponse(
-      const std::string& socket_url,
-      const std::string& socket_host,
-      const std::string& socket_path,
+      base::StringPiece url,
       const std::vector<std::string>& sub_protocols,
-      const url::Origin& origin,
-      const GURL& site_for_cookies,
       const WebSocketExtraHeaders& send_additional_request_headers,
       const WebSocketExtraHeaders& extra_request_headers,
       const std::string& response_body) {
     ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
 
+    const GURL socket_url(url);
+    const std::string socket_host = GetHostAndOptionalPort(socket_url);
+    const std::string socket_path = socket_url.path();
+
     url_request_context_host_.SetExpectations(
         WebSocketStandardRequest(
-            socket_path, socket_host, origin,
+            socket_path, socket_host, Origin(),
             WebSocketExtraHeadersToString(send_additional_request_headers),
             WebSocketExtraHeadersToString(extra_request_headers)),
         response_body);
     CreateAndConnectStream(
-        GURL(socket_url), sub_protocols, origin, site_for_cookies,
+        socket_url, sub_protocols, Origin(), SiteForCookies(),
         WebSocketExtraHeadersToString(send_additional_request_headers),
         nullptr);
   }
@@ -319,36 +321,33 @@
   // string.  This can save space in case of a very large response.
   // Only for HTTP/1-based WebSockets.
   void CreateAndConnectStringResponse(
-      const std::string& socket_url,
-      const std::string& socket_host,
-      const std::string& socket_path,
+      base::StringPiece url,
       const std::vector<std::string>& sub_protocols,
-      const url::Origin& origin,
-      const GURL& site_for_cookies,
       const std::string& extra_response_headers) {
     ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
 
+    const GURL socket_url(url);
+    const std::string socket_host = GetHostAndOptionalPort(socket_url);
+    const std::string socket_path = socket_url.path();
+
     url_request_context_host_.SetExpectations(
-        WebSocketStandardRequest(socket_path, socket_host, origin, "", ""),
+        WebSocketStandardRequest(socket_path, socket_host, Origin(), "", ""),
         WebSocketStandardResponse(extra_response_headers));
-    CreateAndConnectStream(GURL(socket_url), sub_protocols, origin,
-                           site_for_cookies, "", nullptr);
+    CreateAndConnectStream(socket_url, sub_protocols, Origin(),
+                           SiteForCookies(), "", nullptr);
   }
 
   // Like CreateAndConnectStandard(), but take raw mock data.
   void CreateAndConnectRawExpectations(
-      const std::string& socket_url,
+      base::StringPiece url,
       const std::vector<std::string>& sub_protocols,
-      const url::Origin& origin,
-      const GURL& site_for_cookies,
       const std::string& send_additional_request_headers,
       std::unique_ptr<SequencedSocketData> socket_data) {
     ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
 
     url_request_context_host_.AddRawExpectations(std::move(socket_data));
-    CreateAndConnectStream(GURL(socket_url), sub_protocols, origin,
-                           site_for_cookies, send_additional_request_headers,
-                           std::move(timer_));
+    CreateAndConnectStream(GURL(url), sub_protocols, Origin(), SiteForCookies(),
+                           send_additional_request_headers, std::move(timer_));
   }
 
  private:
@@ -405,8 +404,7 @@
       const std::string& extensions_header_value) {
     AddSSLData();
     CreateAndConnectStandard(
-        "wss://www.example.org/testing_path", "www.example.org",
-        "/testing_path", NoSubProtocols(), Origin(), Url(), {}, {},
+        "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
         {{"Sec-WebSocket-Extensions", extensions_header_value}});
     WaitUntilConnectDone();
   }
@@ -489,7 +487,7 @@
     const std::string request =
         base::StringPrintf(request2format, base64_user_pass.c_str());
     CreateAndConnectRawExpectations(
-        url, NoSubProtocols(), Origin(), Url(), "",
+        url, NoSubProtocols(), "",
         helper_.BuildSocketData2(request, response2));
   }
 
@@ -556,8 +554,8 @@
 
   AddSSLData();
   EXPECT_FALSE(url_request_);
-  CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                           {});
   EXPECT_FALSE(request_info_);
   EXPECT_FALSE(response_info_);
   EXPECT_TRUE(url_request_);
@@ -596,9 +594,8 @@
       "hoge: piyo\r\n"
       "\r\n";
 
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kResponse);
   EXPECT_FALSE(request_info_);
   EXPECT_FALSE(response_info_);
   WaitUntilConnectDone();
@@ -652,8 +649,7 @@
 TEST_P(WebSocketStreamCreateTest, HandshakeOverrideHeaders) {
   WebSocketExtraHeaders additional_headers(
       {{"User-Agent", "OveRrIde"}, {"rAnDomHeader", "foobar"}});
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(),
+  CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(),
                            additional_headers, additional_headers, {});
   EXPECT_FALSE(request_info_);
   EXPECT_FALSE(response_info_);
@@ -671,8 +667,8 @@
 
 // Confirm that the stream isn't established until the message loop runs.
 TEST_P(WebSocketStreamCreateTest, NeedsToRunLoop) {
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
+                           {});
   EXPECT_FALSE(has_failed());
   EXPECT_FALSE(stream_);
 }
@@ -681,8 +677,7 @@
 TEST_P(WebSocketMultiProtocolStreamCreateTest, PathIsUsed) {
   AddSSLData();
   CreateAndConnectStandard("wss://www.example.org/testing_path",
-                           "www.example.org", "/testing_path", NoSubProtocols(),
-                           Origin(), Url(), {}, {}, {});
+                           NoSubProtocols(), {}, {}, {});
   WaitUntilConnectDone();
   EXPECT_FALSE(has_failed());
   EXPECT_TRUE(stream_);
@@ -695,8 +690,7 @@
   sub_protocols.push_back("chatv11.chromium.org");
   sub_protocols.push_back("chatv20.chromium.org");
   CreateAndConnectStandard(
-      "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
-      sub_protocols, Origin(), Url(), {},
+      "wss://www.example.org/testing_path", sub_protocols, {},
       {{"Sec-WebSocket-Protocol",
         "chatv11.chromium.org, chatv20.chromium.org"}},
       {{"Sec-WebSocket-Protocol", "chatv20.chromium.org"}});
@@ -712,8 +706,7 @@
 
   AddSSLData();
   CreateAndConnectStandard(
-      "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
-      NoSubProtocols(), Origin(), Url(), {}, {},
+      "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
       {{"Sec-WebSocket-Protocol", "chatv20.chromium.org"}});
   WaitUntilConnectDone();
   EXPECT_FALSE(stream_);
@@ -748,10 +741,9 @@
   AddSSLData();
   std::vector<std::string> sub_protocols;
   sub_protocols.push_back("chat.example.com");
-  CreateAndConnectStandard(
-      "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
-      sub_protocols, Origin(), Url(), {},
-      {{"Sec-WebSocket-Protocol", "chat.example.com"}}, {});
+  CreateAndConnectStandard("wss://www.example.org/testing_path", sub_protocols,
+                           {}, {{"Sec-WebSocket-Protocol", "chat.example.com"}},
+                           {});
   WaitUntilConnectDone();
   EXPECT_FALSE(stream_);
   EXPECT_TRUE(has_failed());
@@ -767,9 +759,8 @@
   std::vector<std::string> sub_protocols;
   sub_protocols.push_back("chatv11.chromium.org");
   sub_protocols.push_back("chatv20.chromium.org");
-  CreateAndConnectStandard("wss://www.example.org/testing_path",
-                           "www.example.org", "/testing_path", sub_protocols,
-                           Origin(), Url(), {},
+  CreateAndConnectStandard("wss://www.example.org/testing_path", sub_protocols,
+                           {},
                            {{"Sec-WebSocket-Protocol",
                              "chatv11.chromium.org, chatv20.chromium.org"}},
                            {{"Sec-WebSocket-Protocol",
@@ -791,8 +782,7 @@
   sub_protocols.push_back("chatv11.chromium.org");
   sub_protocols.push_back("chatv20.chromium.org");
   CreateAndConnectStandard(
-      "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
-      sub_protocols, Origin(), Url(), {},
+      "wss://www.example.org/testing_path", sub_protocols, {},
       {{"Sec-WebSocket-Protocol",
         "chatv11.chromium.org, chatv20.chromium.org"}},
       {{"Sec-WebSocket-Protocol", "chatv21.chromium.org"}});
@@ -831,8 +821,7 @@
       "\xf2\x48\xcd\xc9\xc9\x07\x00",  // "Hello" DEFLATE compressed
       9));
   CreateAndConnectStandard(
-      "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
-      NoSubProtocols(), Origin(), Url(), {}, {},
+      "wss://www.example.org/testing_path", NoSubProtocols(), {}, {},
       {{"Sec-WebSocket-Extensions", "permessage-deflate"}});
   WaitUntilConnectDone();
 
@@ -922,8 +911,7 @@
 // Additional Sec-WebSocket-Accept headers should be rejected.
 TEST_P(WebSocketStreamCreateTest, DoubleAccept) {
   CreateAndConnectStandard(
-      "ws://www.example.org/", "www.example.org", "/", NoSubProtocols(),
-      Origin(), Url(), {}, {},
+      "ws://www.example.org/", NoSubProtocols(), {}, {},
       {{"Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="}});
   WaitUntilConnectDone();
   EXPECT_FALSE(stream_);
@@ -949,14 +937,13 @@
         "Connection: Upgrade\r\n"
         "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
         "\r\n";
-    CreateAndConnectCustomResponse("wss://www.example.org/", "www.example.org",
-                                   "/", NoSubProtocols(), Origin(), Url(), {},
-                                   {}, kInvalidStatusCodeResponse);
+    CreateAndConnectCustomResponse("wss://www.example.org/", NoSubProtocols(),
+                                   {}, {}, kInvalidStatusCodeResponse);
   } else {
     DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
     SetHttp2ResponseStatus("101");
-    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                             {});
   }
 
   WaitUntilConnectDone();
@@ -995,14 +982,13 @@
         "Location: wss://www.example.org/other\r\n"
         "\r\n"
         "<title>Moved</title><h1>Moved</h1>";
-    CreateAndConnectCustomResponse("wss://www.example.org/", "www.example.org",
-                                   "/", NoSubProtocols(), Origin(), Url(), {},
-                                   {}, kRedirectResponse);
+    CreateAndConnectCustomResponse("wss://www.example.org/", NoSubProtocols(),
+                                   {}, {}, kRedirectResponse);
   } else {
     DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
     SetHttp2ResponseStatus("302");
-    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                             {});
   }
   WaitUntilConnectDone();
 
@@ -1023,9 +1009,8 @@
       "Connection: Upgrade\r\n"
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMalformedResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMalformedResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: Invalid status line",
@@ -1041,9 +1026,8 @@
       "Connection: Upgrade\r\n"
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMissingUpgradeResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMissingUpgradeResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing",
@@ -1061,8 +1045,7 @@
 
 // There must only be one upgrade header.
 TEST_P(WebSocketStreamCreateTest, DoubleUpgradeHeader) {
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {},
+  CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
                            {{"Upgrade", "HTTP/2.0"}});
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
@@ -1079,9 +1062,8 @@
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "Upgrade: hogefuga\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMissingUpgradeResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMissingUpgradeResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: "
@@ -1098,9 +1080,8 @@
       "Upgrade: websocket\r\n"
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMissingConnectionResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMissingConnectionResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: "
@@ -1126,9 +1107,8 @@
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "Connection: hogefuga\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMissingConnectionResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMissingConnectionResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: "
@@ -1144,9 +1124,8 @@
       "Connection: Upgrade, Keep-Alive\r\n"
       "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kAdditionalConnectionTokenResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kAdditionalConnectionTokenResponse);
   WaitUntilConnectDone();
   EXPECT_FALSE(has_failed());
   EXPECT_TRUE(stream_);
@@ -1161,9 +1140,8 @@
       "Upgrade: websocket\r\n"
       "Connection: Upgrade\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kMissingAcceptResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kMissingAcceptResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: "
@@ -1188,9 +1166,8 @@
       "Connection: Upgrade\r\n"
       "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n"
       "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kIncorrectAcceptResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kIncorrectAcceptResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: "
@@ -1200,8 +1177,8 @@
 
 // Cancellation works.
 TEST_P(WebSocketStreamCreateTest, Cancellation) {
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
+                           {});
   stream_request_.reset();
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
@@ -1216,8 +1193,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(
       MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
@@ -1231,8 +1208,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(
       MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
@@ -1246,8 +1223,8 @@
   auto timer = std::make_unique<MockWeakTimer>(false, false);
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
   SetTimer(std::move(timer));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   EXPECT_FALSE(has_failed());
   ASSERT_TRUE(weak_timer.get());
   EXPECT_TRUE(weak_timer->IsRunning());
@@ -1267,8 +1244,8 @@
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
 
   SetTimer(std::move(timer));
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  CreateAndConnectStandard("ws://www.example.org/", NoSubProtocols(), {}, {},
+                           {});
   ASSERT_TRUE(weak_timer);
   EXPECT_TRUE(weak_timer->IsRunning());
 
@@ -1287,8 +1264,8 @@
   auto timer = std::make_unique<MockWeakTimer>(false, false);
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
   SetTimer(std::move(timer));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   ASSERT_TRUE(weak_timer.get());
   EXPECT_TRUE(weak_timer->IsRunning());
 
@@ -1304,8 +1281,8 @@
 TEST_P(WebSocketStreamCreateTest, CancellationDuringConnect) {
   std::unique_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   stream_request_.reset();
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
@@ -1320,8 +1297,7 @@
   SequencedSocketData* socket_data(
       new SequencedSocketData(NULL, 0, writes, arraysize(writes)));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "",
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
                                   base::WrapUnique(socket_data));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(socket_data->AllWriteDataConsumed());
@@ -1345,8 +1321,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(
       BuildSocketData(reads, writes));
   SequencedSocketData* socket_data_raw_ptr = socket_data.get();
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
   stream_request_.reset();
@@ -1370,8 +1346,7 @@
     set_cookie_headers += base::StringPrintf("Set-Cookie: ws-%d=1\r\n", i);
   }
   ASSERT_GT(set_cookie_headers.size(), 256U * 1024U);
-  CreateAndConnectStringResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(),
+  CreateAndConnectStringResponse("ws://www.example.org/", NoSubProtocols(),
                                  set_cookie_headers);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
@@ -1399,8 +1374,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(
       BuildSocketData(reads, writes));
   SequencedSocketData* socket_data_raw_ptr = socket_data.get();
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
   EXPECT_TRUE(has_failed());
@@ -1429,8 +1404,7 @@
       std::move(ssl_socket_data));
   std::unique_ptr<SequencedSocketData> raw_socket_data(BuildNullSocketData());
   CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "",
-                                  std::move(raw_socket_data));
+                                  "", std::move(raw_socket_data));
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(has_failed());
@@ -1452,8 +1426,8 @@
   url_request_context_host_.AddSSLSocketDataProvider(
       std::make_unique<SSLSocketDataProvider>(ASYNC, OK));
   url_request_context_host_.AddRawExpectations(BuildNullSocketData());
-  CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                           {});
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(ssl_error_callbacks_);
@@ -1466,9 +1440,8 @@
 // If the server requests authorisation, but we have no credentials, the
 // connection should fail cleanly.
 TEST_P(WebSocketStreamCreateBasicAuthTest, FailureNoCredentials) {
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kUnauthorizedResponse);
+  CreateAndConnectCustomResponse("ws://www.example.org/", NoSubProtocols(), {},
+                                 {}, kUnauthorizedResponse);
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("HTTP Authentication failed; no valid credentials available",
@@ -1502,8 +1475,7 @@
       helper_.BuildSocketData1(kUnauthorizedResponse));
 
   CreateAndConnectRawExpectations(
-      "ws://FooBar:pass@www.example.org/", NoSubProtocols(), Origin(), Url(),
-      "",
+      "ws://FooBar:pass@www.example.org/", NoSubProtocols(), "",
       helper_.BuildSocketData2(kAuthorizedRequest,
                                WebSocketStandardResponse(std::string())));
   WaitUntilConnectDone();
@@ -1523,8 +1495,7 @@
     MockRead reads[] = {MockRead(ASYNC, ERR_IO_PENDING, 0)};
     MockWrite writes[] = {MockWrite(ASYNC, 1, request.c_str())};
     CreateAndConnectRawExpectations("wss://www.example.org/", NoSubProtocols(),
-                                    Origin(), Url(), "",
-                                    BuildSocketData(reads, writes));
+                                    "", BuildSocketData(reads, writes));
     base::RunLoop().RunUntilIdle();
     stream_request_.reset();
 
@@ -1536,8 +1507,8 @@
                   WebSocketHandshakeStreamBase::HandshakeResult::INCOMPLETE)));
   } else {
     DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
-    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                             {});
     stream_request_.reset();
 
     auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
@@ -1555,15 +1526,15 @@
 
   if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
     // This is a dummy transaction to avoid crash in ~TestURLRequestContext().
-    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                             {});
   } else {
     DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
     base::HistogramTester histogram_tester;
 
     SetResetWebSocketHttp2Stream(true);
-    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
-                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    CreateAndConnectStandard("wss://www.example.org/", NoSubProtocols(), {}, {},
+                             {});
     base::RunLoop().RunUntilIdle();
     stream_request_.reset();
 
@@ -1600,8 +1571,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(
       BuildSocketData(reads, writes));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
 
@@ -1635,8 +1606,8 @@
   std::unique_ptr<SequencedSocketData> socket_data(
       BuildSocketData(reads, writes));
   url_request_context_host_.SetProxyConfig("https=proxy:8000");
-  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data));
+  CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), "",
+                                  std::move(socket_data));
   WaitUntilConnectDone();
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Establishing a tunnel via proxy server failed.",
diff --git a/remoting/protocol/webrtc_dummy_video_encoder.cc b/remoting/protocol/webrtc_dummy_video_encoder.cc
index d0e2b50..49e5e9d2 100644
--- a/remoting/protocol/webrtc_dummy_video_encoder.cc
+++ b/remoting/protocol/webrtc_dummy_video_encoder.cc
@@ -134,7 +134,9 @@
 
 webrtc::EncodedImageCallback::Result WebrtcDummyVideoEncoder::SendEncodedFrame(
     const WebrtcVideoEncoder::EncodedFrame& frame,
-    base::TimeTicks capture_time) {
+    base::TimeTicks capture_time,
+    base::TimeTicks encode_started_time,
+    base::TimeTicks encode_finished_time) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   uint8_t* buffer = reinterpret_cast<uint8_t*>(
       base::string_as_array(const_cast<std::string*>(&frame.data)));
@@ -153,10 +155,16 @@
   encoded_image._frameType =
       frame.key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta;
   int64_t capture_time_ms = (capture_time - base::TimeTicks()).InMilliseconds();
+  int64_t encode_started_time_ms =
+      (encode_started_time - base::TimeTicks()).InMilliseconds();
+  int64_t encode_finished_time_ms =
+      (encode_finished_time - base::TimeTicks()).InMilliseconds();
   encoded_image.capture_time_ms_ = capture_time_ms;
   encoded_image._timeStamp = static_cast<uint32_t>(capture_time_ms * 90);
   encoded_image.playout_delay_.min_ms = 0;
   encoded_image.playout_delay_.max_ms = 0;
+  encoded_image.timing_.encode_start_ms = encode_started_time_ms;
+  encoded_image.timing_.encode_finish_ms = encode_finished_time_ms;
 
   webrtc::CodecSpecificInfo codec_specific_info;
   memset(&codec_specific_info, 0, sizeof(codec_specific_info));
@@ -280,7 +288,9 @@
 webrtc::EncodedImageCallback::Result
 WebrtcDummyVideoEncoderFactory::SendEncodedFrame(
     const WebrtcVideoEncoder::EncodedFrame& frame,
-    base::TimeTicks capture_time) {
+    base::TimeTicks capture_time,
+    base::TimeTicks encode_started_time,
+    base::TimeTicks encode_finished_time) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   base::AutoLock lock(lock_);
   if (encoders_.size() != 1) {
@@ -288,7 +298,8 @@
     return webrtc::EncodedImageCallback::Result(
         webrtc::EncodedImageCallback::Result::ERROR_SEND_FAILED);
   }
-  return encoders_.front()->SendEncodedFrame(frame, capture_time);
+  return encoders_.front()->SendEncodedFrame(
+      frame, capture_time, encode_started_time, encode_finished_time);
 }
 
 void WebrtcDummyVideoEncoderFactory::RegisterEncoderSelectedCallback(
diff --git a/remoting/protocol/webrtc_dummy_video_encoder.h b/remoting/protocol/webrtc_dummy_video_encoder.h
index c8d2f468..58627e00 100644
--- a/remoting/protocol/webrtc_dummy_video_encoder.h
+++ b/remoting/protocol/webrtc_dummy_video_encoder.h
@@ -53,7 +53,9 @@
 
   webrtc::EncodedImageCallback::Result SendEncodedFrame(
       const WebrtcVideoEncoder::EncodedFrame& frame,
-      base::TimeTicks capture_time);
+      base::TimeTicks capture_time,
+      base::TimeTicks encode_started_time,
+      base::TimeTicks encode_finished_time);
 
  private:
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
@@ -88,7 +90,9 @@
 
   webrtc::EncodedImageCallback::Result SendEncodedFrame(
       const WebrtcVideoEncoder::EncodedFrame& packet,
-      base::TimeTicks capture_time);
+      base::TimeTicks capture_time,
+      base::TimeTicks encode_started_time,
+      base::TimeTicks encode_finished_time);
 
   // Callback will be called once the dummy encoder has been created on
   // |main_task_runner_|.
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
index 4b83060..03dfd0c 100644
--- a/remoting/protocol/webrtc_video_stream.cc
+++ b/remoting/protocol/webrtc_video_stream.cc
@@ -265,7 +265,9 @@
 
   webrtc::EncodedImageCallback::Result result =
       webrtc_transport_->video_encoder_factory()->SendEncodedFrame(
-          *frame, current_frame_stats_->capture_started_time);
+          *frame, current_frame_stats_->capture_started_time,
+          current_frame_stats_->encode_started_time,
+          current_frame_stats_->encode_ended_time);
   if (result.error != webrtc::EncodedImageCallback::Result::OK) {
     // TODO(sergeyu): Stop the stream.
     LOG(ERROR) << "Failed to send video frame.";
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index a88a2ad..c401375 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -40,8 +40,7 @@
     if (!extra_header.empty())
       response.headers->AddHeader(extra_header);
 
-    client_ptr_->OnReceiveResponse(response, base::nullopt /* ssl_info */,
-                                   nullptr /* downloaded_file */);
+    client_ptr_->OnReceiveResponse(response, nullptr /* downloaded_file */);
   }
 
   void NotifyClientOnComplete(int error_code) {
diff --git a/services/network/proxy_service_mojo.cc b/services/network/proxy_service_mojo.cc
index d1c56147..a7bf532 100644
--- a/services/network/proxy_service_mojo.cc
+++ b/services/network/proxy_service_mojo.cc
@@ -17,7 +17,8 @@
 
 namespace network {
 
-std::unique_ptr<net::ProxyResolutionService> CreateProxyServiceUsingMojoFactory(
+std::unique_ptr<net::ProxyResolutionService>
+CreateProxyResolutionServiceUsingMojoFactory(
     proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     std::unique_ptr<net::PacFileFetcher> pac_file_fetcher,
diff --git a/services/network/proxy_service_mojo.h b/services/network/proxy_service_mojo.h
index 9827ae0..7cb5386e 100644
--- a/services/network/proxy_service_mojo.h
+++ b/services/network/proxy_service_mojo.h
@@ -22,8 +22,8 @@
 
 namespace network {
 
-// Creates a proxy service that uses |mojo_proxy_factory| to create and connect
-// to a Mojo proxy resolver service. This proxy service polls
+// Creates a proxy resolution service that uses |mojo_proxy_factory| to create
+// and connect to a Mojo proxy resolver service. This proxy service polls
 // |proxy_config_service| to notice when the proxy settings change.
 //
 // |pac_file_fetcher| specifies the dependency to use for downloading
@@ -36,7 +36,8 @@
 // should use for any DNS queries. It must remain valid throughout the
 // lifetime of the ProxyResolutionService.
 COMPONENT_EXPORT(NETWORK_SERVICE)
-std::unique_ptr<net::ProxyResolutionService> CreateProxyServiceUsingMojoFactory(
+std::unique_ptr<net::ProxyResolutionService>
+CreateProxyResolutionServiceUsingMojoFactory(
     proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     std::unique_ptr<net::PacFileFetcher> pac_file_fetcher,
diff --git a/services/network/public/cpp/cors/cors_url_loader.cc b/services/network/public/cpp/cors/cors_url_loader.cc
index d5abecc..96d1183d 100644
--- a/services/network/public/cpp/cors/cors_url_loader.cc
+++ b/services/network/public/cpp/cors/cors_url_loader.cc
@@ -127,7 +127,6 @@
 
 void CORSURLLoader::OnReceiveResponse(
     const ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     mojom::DownloadedTempFilePtr downloaded_file) {
   DCHECK(network_loader_);
   DCHECK(forwarding_client_);
@@ -147,7 +146,7 @@
       return;
     }
   }
-  forwarding_client_->OnReceiveResponse(response_head, ssl_info,
+  forwarding_client_->OnReceiveResponse(response_head,
                                         std::move(downloaded_file));
 }
 
diff --git a/services/network/public/cpp/cors/cors_url_loader.h b/services/network/public/cpp/cors/cors_url_loader.h
index 3c8efcd..31b18ba 100644
--- a/services/network/public/cpp/cors/cors_url_loader.h
+++ b/services/network/public/cpp/cors/cors_url_loader.h
@@ -45,7 +45,6 @@
 
   // mojom::URLLoaderClient overrides:
   void OnReceiveResponse(const ResourceResponseHead& head,
-                         const base::Optional<net::SSLInfo>& ssl_info,
                          mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const ResourceResponseHead& head) override;
diff --git a/services/network/public/cpp/network_param_ipc_traits.h b/services/network/public/cpp/network_param_ipc_traits.h
index 1f8ed90e..50c5b67 100644
--- a/services/network/public/cpp/network_param_ipc_traits.h
+++ b/services/network/public/cpp/network_param_ipc_traits.h
@@ -384,11 +384,8 @@
   IPC_STRUCT_TRAITS_MEMBER(did_service_worker_navigation_preload)
   IPC_STRUCT_TRAITS_MEMBER(previews_state)
   IPC_STRUCT_TRAITS_MEMBER(effective_connection_type)
-  IPC_STRUCT_TRAITS_MEMBER(certificate)
   IPC_STRUCT_TRAITS_MEMBER(cert_status)
-  IPC_STRUCT_TRAITS_MEMBER(ssl_connection_status)
-  IPC_STRUCT_TRAITS_MEMBER(ssl_key_exchange_group)
-  IPC_STRUCT_TRAITS_MEMBER(signed_certificate_timestamps)
+  IPC_STRUCT_TRAITS_MEMBER(ssl_info)
   IPC_STRUCT_TRAITS_MEMBER(cors_exposed_header_names)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 085ab85c..b62243ae 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -202,6 +202,9 @@
   bool allow_download = false;
 
   // Whether to intercept headers to pass back to the renderer.
+  // This also enables reporting of SSLInfo in URLLoaderClient's
+  // OnResponseReceived and OnComplete, as well as invocation of
+  // OnTransferSizeUpdated().
   bool report_raw_headers = false;
 
   // Whether or not to request a Preview version of the resource or let the
diff --git a/services/network/public/cpp/resource_response.cc b/services/network/public/cpp/resource_response.cc
index 777a2b4..e1726d87 100644
--- a/services/network/public/cpp/resource_response.cc
+++ b/services/network/public/cpp/resource_response.cc
@@ -52,12 +52,8 @@
   new_response->head.cache_storage_cache_name = head.cache_storage_cache_name;
   new_response->head.previews_state = head.previews_state;
   new_response->head.effective_connection_type = head.effective_connection_type;
-  new_response->head.certificate = head.certificate;
   new_response->head.cert_status = head.cert_status;
-  new_response->head.ssl_connection_status = head.ssl_connection_status;
-  new_response->head.ssl_key_exchange_group = head.ssl_key_exchange_group;
-  new_response->head.signed_certificate_timestamps =
-      head.signed_certificate_timestamps;
+  new_response->head.ssl_info = head.ssl_info;
   new_response->head.cors_exposed_header_names = head.cors_exposed_header_names;
   new_response->head.did_service_worker_navigation_preload =
       head.did_service_worker_navigation_preload;
diff --git a/services/network/public/cpp/resource_response_info.cc b/services/network/public/cpp/resource_response_info.cc
index c47e87b..89a167e 100644
--- a/services/network/public/cpp/resource_response_info.cc
+++ b/services/network/public/cpp/resource_response_info.cc
@@ -26,8 +26,6 @@
       previews_state(0),
       effective_connection_type(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       cert_status(0),
-      ssl_connection_status(0),
-      ssl_key_exchange_group(0),
       did_service_worker_navigation_preload(false),
       blocked_cross_site_document(false) {}
 
diff --git a/services/network/public/cpp/resource_response_info.h b/services/network/public/cpp/resource_response_info.h
index 9b9c6c7..c506efab 100644
--- a/services/network/public/cpp/resource_response_info.h
+++ b/services/network/public/cpp/resource_response_info.h
@@ -155,29 +155,14 @@
   // only for responses that correspond to main frame requests.
   net::EffectiveConnectionType effective_connection_type;
 
-  // DER-encoded X509Certificate certificate chain. Only present if the renderer
-  // process set report_raw_headers to true.
-  std::vector<std::string> certificate;
-
   // Bitmask of status info of the SSL certificate. See cert_status_flags.h for
   // values.
   net::CertStatus cert_status;
 
-  // Information about the SSL connection itself. See
-  // ssl_connection_status_flags.h for values. The protocol version,
-  // ciphersuite, and compression in use are encoded within. Only present if
-  // the renderer process set report_raw_headers to true.
-  int ssl_connection_status;
-
-  // The key exchange group used by the SSL connection or zero if unknown or not
-  // applicable. Only present if the renderer process set report_raw_headers to
-  // true.
-  uint16_t ssl_key_exchange_group;
-
-  // List of Signed Certificate Timestamps (SCTs) and their corresponding
-  // validation status. Only present if the renderer process set
-  // report_raw_headers to true.
-  net::SignedCertificateTimestampAndStatusList signed_certificate_timestamps;
+  // Only provided if kURLLoadOptionsSendSSLInfoWithResponse was specified to
+  // the URLLoaderFactory::CreateLoaderAndStart option or
+  // if ResourceRequest::report_raw_headers is set.
+  base::Optional<net::SSLInfo> ssl_info;
 
   // In case this is a CORS response fetched by a ServiceWorker, this is the
   // set of headers that should be exposed.
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 186b686..ae9f135 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -270,7 +270,6 @@
 
   // mojom::URLLoaderClient implementation;
   void OnReceiveResponse(const ResourceResponseHead& response_head,
-                         const base::Optional<net::SSLInfo>& ssl_info,
                          mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const ResourceResponseHead& response_head) override;
@@ -1304,7 +1303,6 @@
 
 void SimpleURLLoaderImpl::OnReceiveResponse(
     const ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     mojom::DownloadedTempFilePtr downloaded_file) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (request_state_->response_info) {
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index f242869e..04c7c38 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -1502,8 +1502,7 @@
           response_info.headers =
               new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
                   headers.c_str(), headers.size()));
-          client_->OnReceiveResponse(response_info,
-                                     base::Optional<net::SSLInfo>(), nullptr);
+          client_->OnReceiveResponse(response_info, nullptr);
           break;
         }
         case TestLoaderEvent::kReceived401Response: {
@@ -1512,8 +1511,7 @@
           response_info.headers =
               new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
                   headers.c_str(), headers.size()));
-          client_->OnReceiveResponse(response_info,
-                                     base::Optional<net::SSLInfo>(), nullptr);
+          client_->OnReceiveResponse(response_info, nullptr);
           break;
         }
         case TestLoaderEvent::kReceived501Response: {
@@ -1522,8 +1520,7 @@
           response_info.headers =
               new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
                   headers.c_str(), headers.size()));
-          client_->OnReceiveResponse(response_info,
-                                     base::Optional<net::SSLInfo>(), nullptr);
+          client_->OnReceiveResponse(response_info, nullptr);
           break;
         }
         case TestLoaderEvent::kBodyBufferReceived: {
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index b737757..9441f68 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -213,14 +213,15 @@
                         TCPServerSocket& socket)
       => (int32 result, net.interfaces.IPEndPoint? local_addr_out);
 
-  // Creates a TCP socket connected to |remote_addr|. |observer| will be used
-  // to listen for any network connection error on the newly established
-  // connection. The socket created can only be used for the purpose specified
-  // in |traffic_annotation|, and cannot be re-used for other purposes.
-  // |local_addr| should be set to null unless the caller wants to bind the
-  // socket to a specific address and port. On success, |result| is net::OK.
-  // Caller is to use |send_stream| to send data and |receive_stream| to receive
-  // data over the connection. On failure, |result| is a network error code.
+  // Creates a TCP socket connected to |remote_addr|. |observer| if non-null
+  // will be used to listen for any network connection error on the newly
+  // established connection. The socket created can only be used for the purpose
+  // specified in |traffic_annotation|, and cannot be re-used for other
+  // purposes. |local_addr| should be set to null unless the caller wants to
+  // bind the socket to a specific address and port. On success, |result| is
+  // net::OK. Caller is to use |send_stream| to send data and |receive_stream|
+  // to receive data over the connection. On failure, |result| is a network
+  // error code.
   //
   // Any sockets that are created but are yet to be destroyed will be destroyed
   // when NetworkContext goes away.
@@ -229,7 +230,7 @@
       net.interfaces.AddressList remote_addr_list,
       MutableNetworkTrafficAnnotationTag traffic_annotation,
       TCPConnectedSocket& socket,
-      TCPConnectedSocketObserver observer)
+      TCPConnectedSocketObserver? observer)
      => (int32 result,
          handle<data_pipe_consumer>? receive_stream,
          handle<data_pipe_producer>? send_stream);
diff --git a/services/network/public/mojom/tcp_socket.mojom b/services/network/public/mojom/tcp_socket.mojom
index 0367f3a..452f43fa 100644
--- a/services/network/public/mojom/tcp_socket.mojom
+++ b/services/network/public/mojom/tcp_socket.mojom
@@ -35,16 +35,17 @@
 // Represents a TCP server socket that has been successfully bound to a local
 // address. Caller can close the socket by destroying the interface pointer.
 interface TCPServerSocket {
-  // Waits for an incoming connection request. On success, returns net::OK,
-  // |remote_addr| represents the peer address, |connected_socket| is the new
-  // connection established. Caller uses |send_stream| to send data and
-  // |receive_stream| for receiving data over the new connection. On failure,
-  // |net_error| is a net error code and other fields are null.
-  // Up to |backlog| Accept()s can be pending at a time. |backlog| is a
-  // number that is specified when requesting TCPServerSocket. If more than
-  // |backlog| number of Accept()s are outstanding,
+  // Waits for an incoming connection request. |observer| if non-null will be
+  // used to listen for any network connection error on the newly established
+  // connection. On success, returns net::OK, |remote_addr| represents the peer
+  // address, |connected_socket| is the new connection established. Caller uses
+  // |send_stream| to send data and |receive_stream| for receiving data over the
+  // new connection. On failure, |net_error| is a net error code and other
+  // fields are null. Up to |backlog| Accept()s can be pending at a time.
+  // |backlog| is a number that is specified when requesting TCPServerSocket. If
+  // more than |backlog| number of Accept()s are outstanding,
   // net::ERR_INSUFFICIENT_RESOUCES will be returned.
-  Accept(TCPConnectedSocketObserver observer)
+  Accept(TCPConnectedSocketObserver? observer)
       => (int32 net_error,
           net.interfaces.IPEndPoint? remote_addr,
           TCPConnectedSocket? connected_socket,
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index c3e9903..e69c3e9 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -86,10 +86,7 @@
 interface URLLoaderClient {
   // Called when the response head is received.
   // |downloaded_file| is non-null in the 'download_to_file' case.
-  // |ssl_info| is non-null if |kURLLoadOptionsSendSSLInfoWithResponse|
-  // was specified to CreateLoaderAndStart.
   OnReceiveResponse(URLResponseHead head,
-                    SSLInfo? ssl_info,
                     DownloadedTempFile? downloaded_file);
 
   // Called when the request has been redirected. The receiver is expected to
diff --git a/services/network/tcp_connected_socket.cc b/services/network/tcp_connected_socket.cc
index 2962c9cf..b075716 100644
--- a/services/network/tcp_connected_socket.cc
+++ b/services/network/tcp_connected_socket.cc
@@ -27,9 +27,6 @@
       writable_handle_watcher_(FROM_HERE,
                                mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       traffic_annotation_(traffic_annotation) {
-  // TODO(xunjieli): Consider supporting null |observer_|, if there are
-  // consumers who do not care about read/write errors.
-  DCHECK(observer_);
 }
 
 TCPConnectedSocket::TCPConnectedSocket(
@@ -165,7 +162,7 @@
 void TCPConnectedSocket::OnNetworkReadCompleted(int bytes_read) {
   DCHECK(pending_receive_);
 
-  if (bytes_read < 0)
+  if (bytes_read < 0 && observer_)
     observer_->OnReadError(bytes_read);
 
   if (bytes_read <= 0) {
@@ -225,7 +222,7 @@
 void TCPConnectedSocket::OnNetworkWriteCompleted(int bytes_written) {
   DCHECK(pending_send_);
 
-  if (bytes_written < 0)
+  if (bytes_written < 0 && observer_)
     observer_->OnWriteError(bytes_written);
   if (bytes_written <= 0) {
     ShutdownSend();
diff --git a/services/network/tcp_socket_unittest.cc b/services/network/tcp_socket_unittest.cc
index 95ec05e..f2009132 100644
--- a/services/network/tcp_socket_unittest.cc
+++ b/services/network/tcp_socket_unittest.cc
@@ -37,7 +37,11 @@
 // A mock ServerSocket that completes Accept() using a specified result.
 class MockServerSocket : public net::ServerSocket {
  public:
-  MockServerSocket() {}
+  explicit MockServerSocket(
+      std::vector<std::unique_ptr<net::StaticSocketDataProvider>>
+          data_providers)
+      : data_providers_(std::move(data_providers)) {}
+
   ~MockServerSocket() override {}
 
   // net::ServerSocket implementation.
@@ -89,18 +93,11 @@
   }
 
  private:
-  // Must live longer than all SocketDataProviders.
-  const net::MockRead kReads[1] = {
-      net::MockRead(net::ASYNC, net::ERR_IO_PENDING)};
-
   std::unique_ptr<net::StreamSocket> CreateMockAcceptSocket() {
-    auto data_provider = std::make_unique<net::StaticSocketDataProvider>(
-        kReads, arraysize(kReads), nullptr, 0);
-    data_provider->set_connect_data(
-        net::MockConnect(net::SYNCHRONOUS, net::OK));
+    DCHECK_GT(data_providers_.size(), next_data_provider_index_);
     auto mock_socket = std::make_unique<net::MockTCPClientSocket>(
-        net::AddressList(), nullptr /*netlog*/, data_provider.get());
-    data_providers_.push_back(std::move(data_provider));
+        net::AddressList(), nullptr /*netlog*/,
+        data_providers_[next_data_provider_index_++].get());
     EXPECT_EQ(net::OK, mock_socket->Connect(base::DoNothing()));
     return std::move(mock_socket);
   }
@@ -111,6 +108,7 @@
   std::unique_ptr<net::StreamSocket>* accept_socket_;
   base::RunLoop run_loop_;
   std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers_;
+  size_t next_data_provider_index_ = 0;
 };
 
 class TestTCPConnectedSocketObserver
@@ -204,11 +202,9 @@
   // Accepts one connection. Upon successful completion, |callback| will be
   // invoked.
   void AcceptOneConnection(net::CompletionOnceCallback callback) {
-    observer_ = std::make_unique<TestTCPConnectedSocketObserver>();
     server_socket_->Accept(
-        observer_->GetObserverPtr(),
-        base::BindOnce(&TestServer::OnAccept, base::Unretained(this),
-                       std::move(callback)));
+        nullptr, base::BindOnce(&TestServer::OnAccept, base::Unretained(this),
+                                std::move(callback)));
   }
 
   // Sends data over the most recent connection that is established.
@@ -281,7 +277,6 @@
   SocketFactory factory_;
   mojom::TCPServerSocketPtr server_socket_;
   std::vector<mojom::TCPConnectedSocketPtr> connected_sockets_;
-  std::unique_ptr<TestTCPConnectedSocketObserver> observer_;
   mojo::ScopedDataPipeConsumerHandle server_socket_receive_handle_;
   mojo::ScopedDataPipeProducerHandle server_socket_send_handle_;
   mojo::SimpleWatcher readable_handle_watcher_;
@@ -418,10 +413,9 @@
     mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
 
     mojom::TCPConnectedSocketPtr client_socket;
-    TestTCPConnectedSocketObserver observer;
     EXPECT_EQ(net::OK,
               CreateTCPConnectedSocketSync(
-                  mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                  mojo::MakeRequest(&client_socket), nullptr /*observer*/,
                   test.client_addr, server.server_addr(),
                   &client_socket_receive_handle, &client_socket_send_handle));
     ASSERT_EQ(net::OK, accept_callback.WaitForResult());
@@ -429,8 +423,7 @@
     // Test sending data from server to client.
     const char kTestMsg[] = "hello";
     server.SendData(kTestMsg);
-    EXPECT_EQ(kTestMsg,
-              Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+    EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, strlen(kTestMsg)));
 
     // Test sending data from client to server.
     base::RunLoop read_run_loop;
@@ -455,7 +448,6 @@
     mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
     mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
 
-    TestTCPConnectedSocketObserver observer;
     TestServer server(test.server_addr);
     server.Start(1 /*backlog*/);
     net::TestCompletionCallback accept_callback;
@@ -463,7 +455,7 @@
 
     mojom::TCPConnectedSocketPtr client_socket;
     int result = CreateTCPConnectedSocketSync(
-        mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+        mojo::MakeRequest(&client_socket), nullptr /*observer*/,
         test.client_addr, server.server_addr(), &client_socket_receive_handle,
         &client_socket_send_handle);
     // Both net::ERR_INVALID_ARGUMENT and net::ERR_ADDRESS_UNREACHABLE can be
@@ -497,13 +489,12 @@
   // After handling incoming connections, all callbacks should now complete.
   std::vector<mojom::TCPConnectedSocketPtr> client_sockets;
   for (size_t i = 0; i < backlog; ++i) {
-    TestTCPConnectedSocketObserver observer;
     mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
     mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
     mojom::TCPConnectedSocketPtr client_socket;
     EXPECT_EQ(net::OK,
               CreateTCPConnectedSocketSync(
-                  mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                  mojo::MakeRequest(&client_socket), nullptr /*observer*/,
                   base::nullopt /*local_addr*/, server.server_addr(),
                   &client_socket_receive_handle, &client_socket_send_handle));
     client_sockets.push_back(std::move(client_socket));
@@ -520,7 +511,6 @@
   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
   mojom::TCPConnectedSocketPtr client_socket;
 
-  TestTCPConnectedSocketObserver observer;
   const char kTestMsg[] = "hello";
   auto server = std::make_unique<TestServer>();
   server->Start(1 /*backlog*/);
@@ -529,15 +519,14 @@
 
   EXPECT_EQ(net::OK,
             CreateTCPConnectedSocketSync(
-                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                mojo::MakeRequest(&client_socket), observer()->GetObserverPtr(),
                 base::nullopt /*local_addr*/, server->server_addr(),
                 &client_socket_receive_handle, &client_socket_send_handle));
   ASSERT_EQ(net::OK, accept_callback.WaitForResult());
 
   // Send some data from server to client.
   server->SendData(kTestMsg);
-  EXPECT_EQ(kTestMsg,
-            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, strlen(kTestMsg)));
   // Resetting the |server| destroys the TCPConnectedSocket ptr owned by the
   // server.
   server = nullptr;
@@ -557,7 +546,7 @@
   // Send pipe should be closed.
   while (true) {
     base::RunLoop().RunUntilIdle();
-    uint32_t size = arraysize(kTestMsg);
+    uint32_t size = strlen(kTestMsg);
     MojoResult r = client_socket_send_handle->WriteData(
         kTestMsg, &size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
     if (r == MOJO_RESULT_SHOULD_WAIT)
@@ -566,14 +555,13 @@
       break;
   }
   EXPECT_TRUE(client_socket_send_handle->QuerySignalsState().peer_closed());
-  int result = observer.WaitForWriteError();
+  int result = observer()->WaitForWriteError();
   EXPECT_TRUE(result == net::ERR_CONNECTION_RESET ||
               result == net::ERR_CONNECTION_ABORTED)
       << "actual result: " << result;
 }
 
 TEST_F(TCPSocketTest, ReadPipeClosed) {
-  TestTCPConnectedSocketObserver observer;
   const char kTestMsg[] = "hello";
   TestServer server;
   server.Start(1 /*backlog*/);
@@ -585,7 +573,7 @@
   mojom::TCPConnectedSocketPtr client_socket;
   EXPECT_EQ(net::OK,
             CreateTCPConnectedSocketSync(
-                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                mojo::MakeRequest(&client_socket), nullptr /*observer*/,
                 base::nullopt /*local_addr*/, server.server_addr(),
                 &client_socket_receive_handle, &client_socket_send_handle));
   ASSERT_EQ(net::OK, accept_callback.WaitForResult());
@@ -602,7 +590,6 @@
 }
 
 TEST_F(TCPSocketTest, WritePipeClosed) {
-  TestTCPConnectedSocketObserver observer;
   const char kTestMsg[] = "hello";
   TestServer server;
   server.Start(1 /*backlog*/);
@@ -614,7 +601,7 @@
   mojom::TCPConnectedSocketPtr client_socket;
   EXPECT_EQ(net::OK,
             CreateTCPConnectedSocketSync(
-                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                mojo::MakeRequest(&client_socket), nullptr /*observer*/,
                 base::nullopt /*local_addr*/, server.server_addr(),
                 &client_socket_receive_handle, &client_socket_send_handle));
   ASSERT_EQ(net::OK, accept_callback.WaitForResult());
@@ -624,8 +611,7 @@
 
   // Receive should proceed as normal.
   server.SendData(kTestMsg);
-  EXPECT_EQ(kTestMsg,
-            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, strlen(kTestMsg)));
 }
 
 // Tests that if the server socket is destroyed, any connected sockets that it
@@ -634,7 +620,6 @@
   mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
 
-  TestTCPConnectedSocketObserver observer;
   const char kTestMsg[] = "hello";
   TestServer server;
   server.Start(1 /*backlog*/);
@@ -644,7 +629,7 @@
   mojom::TCPConnectedSocketPtr client_socket;
   EXPECT_EQ(net::OK,
             CreateTCPConnectedSocketSync(
-                mojo::MakeRequest(&client_socket), observer.GetObserverPtr(),
+                mojo::MakeRequest(&client_socket), nullptr /*observer*/,
                 base::nullopt /*local_addr*/, server.server_addr(),
                 &client_socket_receive_handle, &client_socket_send_handle));
   ASSERT_EQ(net::OK, accept_callback.WaitForResult());
@@ -655,8 +640,7 @@
 
   // Sending and receiving should still work.
   server.SendData(kTestMsg);
-  EXPECT_EQ(kTestMsg,
-            Read(&client_socket_receive_handle, arraysize(kTestMsg) - 1));
+  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, strlen(kTestMsg)));
 
   base::RunLoop read_run_loop;
   server.StartReading(kTestMsg, read_run_loop.QuitClosure());
@@ -678,11 +662,23 @@
 // implementation completes Accept() in sync and async mode.
 TEST_P(TCPSocketWithMockSocketTest,
        ServerAcceptClientConnectionWithMockSocket) {
-  net::IoMode mode = GetParam();
-  auto mock_server_socket = std::make_unique<MockServerSocket>();
+  net::IoMode accept_mode = GetParam();
+  const uint32_t kBacklog = 10;
+  const net::MockRead kReads[] = {
+      net::MockRead(net::ASYNC, net::ERR_IO_PENDING)};
+  std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers;
+  for (size_t i = 0; i < kBacklog + 1; ++i) {
+    auto provider = std::make_unique<net::StaticSocketDataProvider>(
+        kReads, arraysize(kReads), nullptr, 0);
+    provider->set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+    data_providers.push_back(std::move(provider));
+  }
+  auto mock_server_socket =
+      std::make_unique<MockServerSocket>(std::move(data_providers));
+
   MockServerSocket* mock_server_socket_raw = mock_server_socket.get();
   mojom::TCPServerSocketPtr server_socket;
-  uint32_t kBacklog = 10;
+
   // Use a mock socket to control net::ServerSocket::Accept() behavior.
   CreateServerSocketWithMockSocket(kBacklog, mojo::MakeRequest(&server_socket),
                                    std::move(mock_server_socket));
@@ -693,23 +689,21 @@
   std::vector<std::unique_ptr<net::TestCompletionCallback>> accept_callbacks;
   for (size_t i = 0; i < kBacklog; ++i) {
     auto callback = std::make_unique<net::TestCompletionCallback>();
-    TestTCPConnectedSocketObserver observer;
     server_socket->Accept(
-        observer.GetObserverPtr(),
-        base::BindOnce(
-            [](net::CompletionOnceCallback callback, int result,
-               const base::Optional<net::IPEndPoint>& remote_addr,
-               mojom::TCPConnectedSocketPtr connected_socket,
-               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
-               mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
-              std::move(callback).Run(result);
-            },
-            std::move(callback->callback())));
+        nullptr, base::BindOnce(
+                     [](net::CompletionOnceCallback callback, int result,
+                        const base::Optional<net::IPEndPoint>& remote_addr,
+                        mojom::TCPConnectedSocketPtr connected_socket,
+                        mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+                        mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+                       std::move(callback).Run(result);
+                     },
+                     std::move(callback->callback())));
     accept_callbacks.push_back(std::move(callback));
   }
 
   mock_server_socket_raw->WaitForFirstAccept();
-  mock_server_socket_raw->SetAcceptResult(mode, net::OK);
+  mock_server_socket_raw->SetAcceptResult(accept_mode, net::OK);
   mock_server_socket_raw->CompleteAccept(net::OK);
 
   // First net::ServerSocket::Accept() will complete asynchronously
@@ -722,19 +716,132 @@
   // New Accept() should complete synchronously internally. Make sure this is
   // okay.
   auto callback = std::make_unique<net::TestCompletionCallback>();
-  TestTCPConnectedSocketObserver observer;
   server_socket->Accept(
-      observer.GetObserverPtr(),
+      nullptr, base::BindOnce(
+                   [](net::CompletionOnceCallback callback, int result,
+                      const base::Optional<net::IPEndPoint>& remote_addr,
+                      mojom::TCPConnectedSocketPtr connected_socket,
+                      mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+                      mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+                     std::move(callback).Run(result);
+                   },
+                   std::move(callback->callback())));
+  EXPECT_EQ(net::OK, callback->WaitForResult());
+}
+
+// Tests that TCPServerSocket::Accept() is used with a non-null
+// TCPConnectedSocketObserver and that the observer is invoked when a read error
+// occurs.
+TEST_P(TCPSocketWithMockSocketTest, ServerAcceptWithObserverReadError) {
+  net::IoMode mode = GetParam();
+  const net::MockRead kReadError[] = {net::MockRead(mode, net::ERR_TIMED_OUT)};
+  std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers;
+  std::unique_ptr<net::StaticSocketDataProvider> provider;
+  provider = std::make_unique<net::StaticSocketDataProvider>(
+      kReadError, arraysize(kReadError), nullptr, 0);
+  provider->set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  data_providers.push_back(std::move(provider));
+
+  auto mock_server_socket =
+      std::make_unique<MockServerSocket>(std::move(data_providers));
+  mojom::TCPServerSocketPtr server_socket;
+  CreateServerSocketWithMockSocket(1 /*backlog*/,
+                                   mojo::MakeRequest(&server_socket),
+                                   std::move(mock_server_socket));
+
+  auto callback = std::make_unique<net::TestCompletionCallback>();
+  mojom::TCPConnectedSocketPtr connected_socket;
+  mojo::ScopedDataPipeConsumerHandle receive_handle;
+  mojo::ScopedDataPipeProducerHandle send_handle;
+  server_socket->Accept(
+      observer()->GetObserverPtr(),
       base::BindOnce(
-          [](net::CompletionOnceCallback callback, int result,
+          [](net::CompletionOnceCallback callback,
+             mojom::TCPConnectedSocketPtr* socket_out,
+             mojo::ScopedDataPipeConsumerHandle* consumer_handle,
+             mojo::ScopedDataPipeProducerHandle* producer_handle, int result,
              const base::Optional<net::IPEndPoint>& remote_addr,
              mojom::TCPConnectedSocketPtr connected_socket,
              mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
              mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
             std::move(callback).Run(result);
+            *socket_out = std::move(connected_socket);
+            *consumer_handle = std::move(receive_pipe_handle);
+            *producer_handle = std::move(send_pipe_handle);
           },
-          std::move(callback->callback())));
+          std::move(callback->callback()), &connected_socket, &receive_handle,
+          &send_handle));
   EXPECT_EQ(net::OK, callback->WaitForResult());
+
+  base::RunLoop().RunUntilIdle();
+  uint32_t read_size = 16;
+  std::vector<char> buffer(read_size);
+  MojoResult result = receive_handle->ReadData(buffer.data(), &read_size,
+                                               MOJO_READ_DATA_FLAG_NONE);
+  ASSERT_NE(MOJO_RESULT_OK, result);
+  EXPECT_EQ(net::ERR_TIMED_OUT, observer()->WaitForReadError());
+}
+
+// Tests that TCPServerSocket::Accept() is used with a non-null
+// TCPConnectedSocketObserver and that the observer is invoked when a write
+// error occurs.
+TEST_P(TCPSocketWithMockSocketTest, ServerAcceptWithObserverWriteError) {
+  net::IoMode mode = GetParam();
+  const net::MockRead kReads[] = {net::MockRead(net::SYNCHRONOUS, net::OK)};
+  const net::MockWrite kWriteError[] = {
+      net::MockWrite(mode, net::ERR_TIMED_OUT)};
+  std::vector<std::unique_ptr<net::StaticSocketDataProvider>> data_providers;
+  std::unique_ptr<net::StaticSocketDataProvider> provider;
+  provider = std::make_unique<net::StaticSocketDataProvider>(
+      kReads, arraysize(kReads), kWriteError, arraysize(kWriteError));
+  provider->set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
+  data_providers.push_back(std::move(provider));
+
+  auto mock_server_socket =
+      std::make_unique<MockServerSocket>(std::move(data_providers));
+  mojom::TCPServerSocketPtr server_socket;
+  CreateServerSocketWithMockSocket(1 /*backlog*/,
+                                   mojo::MakeRequest(&server_socket),
+                                   std::move(mock_server_socket));
+
+  auto callback = std::make_unique<net::TestCompletionCallback>();
+  mojom::TCPConnectedSocketPtr connected_socket;
+  mojo::ScopedDataPipeConsumerHandle receive_handle;
+  mojo::ScopedDataPipeProducerHandle send_handle;
+  server_socket->Accept(
+      observer()->GetObserverPtr(),
+      base::BindOnce(
+          [](net::CompletionOnceCallback callback,
+             mojom::TCPConnectedSocketPtr* socket_out,
+             mojo::ScopedDataPipeConsumerHandle* consumer_handle,
+             mojo::ScopedDataPipeProducerHandle* producer_handle, int result,
+             const base::Optional<net::IPEndPoint>& remote_addr,
+             mojom::TCPConnectedSocketPtr connected_socket,
+             mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
+             mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
+            std::move(callback).Run(result);
+            *socket_out = std::move(connected_socket);
+            *consumer_handle = std::move(receive_pipe_handle);
+            *producer_handle = std::move(send_pipe_handle);
+          },
+          std::move(callback->callback()), &connected_socket, &receive_handle,
+          &send_handle));
+  EXPECT_EQ(net::OK, callback->WaitForResult());
+
+  const char kTestMsg[] = "abcdefghij";
+
+  // Repeatedly write data to the |send_handle| until write fails.
+  while (true) {
+    base::RunLoop().RunUntilIdle();
+    uint32_t num_bytes = strlen(kTestMsg);
+    MojoResult result = send_handle->WriteData(&kTestMsg, &num_bytes,
+                                               MOJO_WRITE_DATA_FLAG_NONE);
+    if (result == MOJO_RESULT_SHOULD_WAIT)
+      continue;
+    if (result != MOJO_RESULT_OK)
+      break;
+  }
+  EXPECT_EQ(net::ERR_TIMED_OUT, observer()->WaitForWriteError());
 }
 
 TEST_P(TCPSocketWithMockSocketTest, ReadAndWriteMultiple) {
@@ -747,7 +854,7 @@
 
   mojom::TCPConnectedSocketPtr client_socket;
   const char kTestMsg[] = "abcdefghij";
-  const size_t kMsgSize = arraysize(kTestMsg) - 1;
+  const size_t kMsgSize = strlen(kTestMsg);
   const int kNumIterations = 3;
   std::vector<net::MockRead> reads;
   std::vector<net::MockWrite> writes;
@@ -805,7 +912,7 @@
 
   mojom::TCPConnectedSocketPtr client_socket;
   const char kTestMsg[] = "abcdefghij";
-  const size_t kMsgSize = arraysize(kTestMsg) - 1;
+  const size_t kMsgSize = strlen(kTestMsg);
   const int kNumIterations = 3;
   std::vector<net::MockRead> reads;
   std::vector<net::MockWrite> writes;
@@ -873,7 +980,7 @@
   net::MockRead reads[] = {net::MockRead(mode, net::ERR_FAILED)};
   const char kTestMsg[] = "hello!";
   net::MockWrite writes[] = {
-      net::MockWrite(mode, kTestMsg, arraysize(kTestMsg) - 1, 0)};
+      net::MockWrite(mode, kTestMsg, strlen(kTestMsg), 0)};
   net::StaticSocketDataProvider data_provider(reads, arraysize(reads), writes,
                                               arraysize(writes));
   data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
@@ -888,7 +995,7 @@
   EXPECT_EQ("", Read(&client_socket_receive_handle, 1));
   EXPECT_EQ(net::ERR_FAILED, observer()->WaitForReadError());
   // Writes can proceed even though there is a read error.
-  uint32_t num_bytes = arraysize(kTestMsg) - 1;
+  uint32_t num_bytes = strlen(kTestMsg);
   EXPECT_EQ(MOJO_RESULT_OK,
             client_socket_send_handle->WriteData(&kTestMsg, &num_bytes,
                                                  MOJO_WRITE_DATA_FLAG_NONE));
@@ -909,9 +1016,8 @@
   mojom::TCPConnectedSocketPtr client_socket;
   net::IoMode mode = GetParam();
   const char kTestMsg[] = "hello!";
-  net::MockRead reads[] = {
-      net::MockRead(mode, kTestMsg, arraysize(kTestMsg) - 1, 0),
-      net::MockRead(mode, net::OK)};
+  net::MockRead reads[] = {net::MockRead(mode, kTestMsg, strlen(kTestMsg), 0),
+                           net::MockRead(mode, net::OK)};
   net::MockWrite writes[] = {net::MockWrite(mode, net::ERR_FAILED)};
   net::StaticSocketDataProvider data_provider(reads, arraysize(reads), writes,
                                               arraysize(writes));
@@ -924,13 +1030,13 @@
                                       std::move(send_pipe.consumer_handle),
                                       std::move(mock_socket));
 
-  uint32_t num_bytes = arraysize(kTestMsg) - 1;
+  uint32_t num_bytes = strlen(kTestMsg);
   EXPECT_EQ(MOJO_RESULT_OK,
             client_socket_send_handle->WriteData(&kTestMsg, &num_bytes,
                                                  MOJO_WRITE_DATA_FLAG_NONE));
   EXPECT_EQ(net::ERR_FAILED, observer()->WaitForWriteError());
   // Reads can proceed even though there is a read error.
-  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, arraysize(kTestMsg)));
+  EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, strlen(kTestMsg)));
 
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(data_provider.AllReadDataConsumed());
diff --git a/services/network/test/test_url_loader_client.cc b/services/network/test/test_url_loader_client.cc
index d201999..8b453e12 100644
--- a/services/network/test/test_url_loader_client.cc
+++ b/services/network/test/test_url_loader_client.cc
@@ -15,14 +15,12 @@
 
 void TestURLLoaderClient::OnReceiveResponse(
     const ResourceResponseHead& response_head,
-    const base::Optional<net::SSLInfo>& ssl_info,
     mojom::DownloadedTempFilePtr downloaded_file) {
   EXPECT_FALSE(has_received_response_);
   EXPECT_FALSE(has_received_cached_metadata_);
   EXPECT_FALSE(has_received_completion_);
   has_received_response_ = true;
   response_head_ = response_head;
-  ssl_info_ = ssl_info;
   downloaded_file_ = std::move(downloaded_file);
   if (quit_closure_for_on_receive_response_)
     quit_closure_for_on_receive_response_.Run();
diff --git a/services/network/test/test_url_loader_client.h b/services/network/test/test_url_loader_client.h
index 85fd005..1cbce06 100644
--- a/services/network/test/test_url_loader_client.h
+++ b/services/network/test/test_url_loader_client.h
@@ -34,7 +34,6 @@
   ~TestURLLoaderClient() override;
 
   void OnReceiveResponse(const ResourceResponseHead& response_head,
-                         const base::Optional<net::SSLInfo>& ssl_info,
                          mojom::DownloadedTempFilePtr downloaded_file) override;
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const ResourceResponseHead& response_head) override;
@@ -59,7 +58,9 @@
   }
   bool has_received_completion() const { return has_received_completion_; }
   const ResourceResponseHead& response_head() const { return response_head_; }
-  const base::Optional<net::SSLInfo>& ssl_info() const { return ssl_info_; }
+  const base::Optional<net::SSLInfo>& ssl_info() const {
+    return response_head_.ssl_info;
+  }
   const net::RedirectInfo& redirect_info() const { return redirect_info_; }
   const std::string& cached_metadata() const { return cached_metadata_; }
   mojo::DataPipeConsumerHandle response_body() { return response_body_.get(); }
@@ -101,7 +102,6 @@
 
   mojo::Binding<mojom::URLLoaderClient> binding_;
   ResourceResponseHead response_head_;
-  base::Optional<net::SSLInfo> ssl_info_;
   mojom::DownloadedTempFilePtr downloaded_file_;
   net::RedirectInfo redirect_info_;
   std::string cached_metadata_;
diff --git a/services/network/test/test_url_loader_factory.cc b/services/network/test/test_url_loader_factory.cc
index 12ffa77..2baee86 100644
--- a/services/network/test/test_url_loader_factory.cc
+++ b/services/network/test/test_url_loader_factory.cc
@@ -83,7 +83,7 @@
   for (auto it = responses_.begin(); it != responses_.end(); ++it) {
     if (it->url == url) {
       CHECK(it->redirects.empty()) << "TODO(jam): handle redirects";
-      client->OnReceiveResponse(it->head, base::nullopt, nullptr);
+      client->OnReceiveResponse(it->head, nullptr);
       mojo::DataPipe data_pipe;
       uint32_t bytes_written = it->content.size();
       CHECK_EQ(MOJO_RESULT_OK, data_pipe.producer_handle->WriteData(
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index fc858937..4a35dce 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -41,6 +41,7 @@
 // content/browser/loader/resource_loader.cc
 void PopulateResourceResponse(net::URLRequest* request,
                               bool is_load_timing_enabled,
+                              bool include_ssl_info,
                               ResourceResponse* response) {
   response->head.request_time = request->request_time();
   response->head.response_time = request->response_time();
@@ -70,6 +71,9 @@
          net::IsCertStatusMinorError(response->head.cert_status)) &&
         net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
     response->head.cert_status = request->ssl_info().cert_status;
+
+    if (include_ssl_info)
+      response->head.ssl_info = request->ssl_info();
   }
 
   response->head.request_start = request->creation_time();
@@ -299,6 +303,10 @@
         << "disabled, as that skips security checks in ResourceDispatcherHost. "
         << "The only acceptable usage is the browser using SimpleURLLoader.";
   }
+  if (report_raw_headers_) {
+    options_ |= mojom::kURLLoadOptionSendSSLInfoWithResponse |
+                mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+  }
   url_request_context_getter_->AddObserver(this);
   binding_.set_connection_error_handler(
       base::BindOnce(&URLLoader::OnConnectionError, base::Unretained(this)));
@@ -445,8 +453,9 @@
   *defer_redirect = true;
 
   scoped_refptr<ResourceResponse> response = new ResourceResponse();
-  PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
-                           response.get());
+  PopulateResourceResponse(
+      url_request_.get(), is_load_timing_enabled_,
+      options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse, response.get());
   if (report_raw_headers_) {
     response->head.raw_request_response_info = BuildRawRequestResponseInfo(
         *url_request_, raw_request_headers_, raw_response_headers_.get());
@@ -529,8 +538,9 @@
   }
 
   response_ = new ResourceResponse();
-  PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
-                           response_.get());
+  PopulateResourceResponse(
+      url_request_.get(), is_load_timing_enabled_,
+      options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse, response_.get());
   if (report_raw_headers_) {
     response_->head.raw_request_response_info = BuildRawRequestResponseInfo(
         *url_request_, raw_request_headers_, raw_response_headers_.get());
@@ -773,10 +783,8 @@
 
 void URLLoader::SendResponseToClient() {
   base::Optional<net::SSLInfo> ssl_info;
-  if (options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse)
-    ssl_info = url_request_->ssl_info();
   mojom::DownloadedTempFilePtr downloaded_file_ptr;
-  url_loader_client_->OnReceiveResponse(response_->head, ssl_info,
+  url_loader_client_->OnReceiveResponse(response_->head,
                                         std::move(downloaded_file_ptr));
 
   net::IOBufferWithSize* metadata =
diff --git a/services/network/url_request_context_builder_mojo.cc b/services/network/url_request_context_builder_mojo.cc
index c9ba9f2..d1f27e39 100644
--- a/services/network/url_request_context_builder_mojo.cc
+++ b/services/network/url_request_context_builder_mojo.cc
@@ -43,7 +43,7 @@
 }
 
 std::unique_ptr<net::ProxyResolutionService>
-URLRequestContextBuilderMojo::CreateProxyService(
+URLRequestContextBuilderMojo::CreateProxyResolutionService(
     std::unique_ptr<net::ProxyConfigService> proxy_config_service,
     net::URLRequestContext* url_request_context,
     net::HostResolver* host_resolver,
@@ -58,7 +58,7 @@
         dhcp_fetcher_factory_->Create(url_request_context);
     std::unique_ptr<net::PacFileFetcher> pac_file_fetcher =
         std::make_unique<net::PacFileFetcherImpl>(url_request_context);
-    return CreateProxyServiceUsingMojoFactory(
+    return CreateProxyResolutionServiceUsingMojoFactory(
         std::move(mojo_proxy_resolver_factory_),
         std::move(proxy_config_service), std::move(pac_file_fetcher),
         std::move(dhcp_pac_file_fetcher), host_resolver, net_log,
@@ -66,7 +66,7 @@
   }
 #endif
 
-  return net::URLRequestContextBuilder::CreateProxyService(
+  return net::URLRequestContextBuilder::CreateProxyResolutionService(
       std::move(proxy_config_service), url_request_context, host_resolver,
       network_delegate, net_log);
 }
diff --git a/services/network/url_request_context_builder_mojo.h b/services/network/url_request_context_builder_mojo.h
index 499d7e9..d7262117 100644
--- a/services/network/url_request_context_builder_mojo.h
+++ b/services/network/url_request_context_builder_mojo.h
@@ -62,7 +62,7 @@
       net::NetworkQualityEstimator* network_quality_estimator);
 
  private:
-  std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+  std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
       std::unique_ptr<net::ProxyConfigService> proxy_config_service,
       net::URLRequestContext* url_request_context,
       net::HostResolver* host_resolver,
diff --git a/services/network/websocket_factory.cc b/services/network/websocket_factory.cc
index cc7c51a..aa22fe7 100644
--- a/services/network/websocket_factory.cc
+++ b/services/network/websocket_factory.cc
@@ -14,12 +14,10 @@
 
 namespace network {
 
-class WebSocketFactory::Delegate final
-    : public WebSocket::Delegate,
-      public base::SupportsWeakPtr<Delegate> {
+class WebSocketFactory::Delegate final : public WebSocket::Delegate {
  public:
   Delegate(WebSocketFactory* factory, int32_t process_id)
-      : factory_(factory), process_id_(process_id) {}
+      : factory_(factory), process_id_(process_id), weak_factory_(this) {}
   ~Delegate() override {}
 
   net::URLRequestContext* GetURLRequestContext() override {
@@ -54,7 +52,7 @@
         process_id, render_frame_id, request_id, resource_type, url, ssl_info,
         fatal,
         base::BindRepeating(&Delegate::OnSSLCertificateErrorResponse,
-                            AsWeakPtr(), ssl_info));
+                            weak_factory_.GetWeakPtr(), ssl_info));
   }
 
   void ReportBadMessage(BadMessageReason reason, WebSocket* impl) override {
@@ -86,6 +84,8 @@
   const int process_id_;
   std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks_;
 
+  base::WeakPtrFactory<Delegate> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
diff --git a/services/network/websocket_factory.h b/services/network/websocket_factory.h
index d40b8ab..31369a3 100644
--- a/services/network/websocket_factory.h
+++ b/services/network/websocket_factory.h
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/containers/unique_ptr_adapters.h"
-#include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "services/network/websocket.h"
@@ -22,8 +21,7 @@
 
 class NetworkContext;
 
-// TODO(yhirano): Implement throttling.
-class WebSocketFactory final : public base::SupportsWeakPtr<WebSocketFactory> {
+class WebSocketFactory final {
  public:
   explicit WebSocketFactory(NetworkContext* context);
   ~WebSocketFactory();
diff --git a/services/network/websocket_throttler_unittest.cc b/services/network/websocket_throttler_unittest.cc
index c0ffce1..0c06866 100644
--- a/services/network/websocket_throttler_unittest.cc
+++ b/services/network/websocket_throttler_unittest.cc
@@ -173,13 +173,13 @@
   EXPECT_EQ(0, throttler.num_previous_failed_connections());
 }
 
-TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_4Pending) {
+TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_3Pending) {
   WebSocketPerProcessThrottler throttler;
   std::vector<WebSocketPerProcessThrottler::PendingConnection> trackers;
-  for (int i = 0; i < 4; ++i)
+  for (int i = 0; i < 3; ++i)
     trackers.push_back(throttler.IssuePendingConnectionTracker());
 
-  EXPECT_EQ(4, throttler.num_pending_connections());
+  EXPECT_EQ(3, throttler.num_pending_connections());
   EXPECT_EQ(0, throttler.num_current_succeeded_connections());
   EXPECT_EQ(0, throttler.num_previous_succeeded_connections());
   EXPECT_EQ(0, throttler.num_current_failed_connections());
@@ -187,13 +187,13 @@
   EXPECT_EQ(base::TimeDelta(), throttler.CalculateDelay());
 }
 
-TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_8Pending) {
+TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_7Pending) {
   WebSocketPerProcessThrottler throttler;
   std::vector<WebSocketPerProcessThrottler::PendingConnection> trackers;
-  for (int i = 0; i < 8; ++i)
+  for (int i = 0; i < 7; ++i)
     trackers.push_back(throttler.IssuePendingConnectionTracker());
 
-  EXPECT_EQ(8, throttler.num_pending_connections());
+  EXPECT_EQ(7, throttler.num_pending_connections());
   EXPECT_EQ(0, throttler.num_current_succeeded_connections());
   EXPECT_EQ(0, throttler.num_previous_succeeded_connections());
   EXPECT_EQ(0, throttler.num_current_failed_connections());
@@ -201,13 +201,13 @@
   EXPECT_LT(base::TimeDelta(), throttler.CalculateDelay());
 }
 
-TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_17Pending) {
+TEST(WebSocketPerProcessThrottlerTest, CalculateDelay_16Pending) {
   WebSocketPerProcessThrottler throttler;
   std::vector<WebSocketPerProcessThrottler::PendingConnection> trackers;
-  for (int i = 0; i < 17; ++i)
+  for (int i = 0; i < 16; ++i)
     trackers.push_back(throttler.IssuePendingConnectionTracker());
 
-  EXPECT_EQ(17, throttler.num_pending_connections());
+  EXPECT_EQ(16, throttler.num_pending_connections());
   EXPECT_EQ(0, throttler.num_current_succeeded_connections());
   EXPECT_EQ(0, throttler.num_previous_succeeded_connections());
   EXPECT_EQ(0, throttler.num_current_failed_connections());
diff --git a/storage/browser/blob/blob_builder_from_stream.cc b/storage/browser/blob/blob_builder_from_stream.cc
index deefc4a..9dff07cd 100644
--- a/storage/browser/blob/blob_builder_from_stream.cc
+++ b/storage/browser/blob/blob_builder_from_stream.cc
@@ -241,9 +241,9 @@
     if (item_->type() == BlobDataItem::Type::kBytesDescription)
       item_->AllocateBytes();
     std::memcpy(item_->mutable_bytes()
-                    .subspan(bytes_previously_written, data.length())
+                    .subspan(bytes_previously_written, data.size())
                     .data(),
-                data.data(), data.length());
+                data.data(), data.size());
     return true;
   }
 
diff --git a/storage/browser/blob/blob_data_builder.cc b/storage/browser/blob/blob_data_builder.cc
index 8e47005..f9c54c9 100644
--- a/storage/browser/blob/blob_data_builder.cc
+++ b/storage/browser/blob/blob_data_builder.cc
@@ -41,11 +41,11 @@
 bool BlobDataBuilder::FutureData::Populate(base::span<const char> data,
                                            size_t offset) const {
   DCHECK(data.data());
-  base::span<char> target = GetDataToPopulate(offset, data.length());
+  base::span<char> target = GetDataToPopulate(offset, data.size());
   if (!target.data())
     return false;
-  DCHECK_EQ(target.length(), data.length());
-  std::memcpy(target.data(), data.data(), data.length());
+  DCHECK_EQ(target.size(), data.size());
+  std::memcpy(target.data(), data.data(), data.size());
   return true;
 }
 
@@ -67,7 +67,7 @@
   checked_end += length;
   if (!checked_end.IsValid() || checked_end.ValueOrDie() > item_->length()) {
     DVLOG(1) << "Invalid offset or length.";
-    return nullptr;
+    return base::span<char>();
   }
   return item_->mutable_bytes().subspan(offset, length);
 }
diff --git a/storage/browser/blob/blob_data_item.cc b/storage/browser/blob/blob_data_item.cc
index 67b02d6..0b3b122 100644
--- a/storage/browser/blob/blob_data_item.cc
+++ b/storage/browser/blob/blob_data_item.cc
@@ -25,7 +25,7 @@
 scoped_refptr<BlobDataItem> BlobDataItem::CreateBytes(
     base::span<const char> bytes) {
   auto item =
-      base::WrapRefCounted(new BlobDataItem(Type::kBytes, 0, bytes.length()));
+      base::WrapRefCounted(new BlobDataItem(Type::kBytes, 0, bytes.size()));
   item->bytes_.assign(bytes.begin(), bytes.end());
   return item;
 }
@@ -134,7 +134,7 @@
 
 void BlobDataItem::PopulateBytes(base::span<const char> data) {
   DCHECK_EQ(type_, Type::kBytesDescription);
-  DCHECK_EQ(length_, data.length());
+  DCHECK_EQ(length_, data.size());
   type_ = Type::kBytes;
   bytes_.assign(data.begin(), data.end());
 }
diff --git a/storage/browser/blob/blob_memory_controller.cc b/storage/browser/blob/blob_memory_controller.cc
index 664f350..028108a 100644
--- a/storage/browser/blob/blob_memory_controller.cc
+++ b/storage/browser/blob/blob_memory_controller.cc
@@ -217,7 +217,7 @@
   file.SetLength(total_size_bytes);
   int bytes_written = 0;
   for (const auto& item : data) {
-    size_t length = item.length();
+    size_t length = item.size();
     size_t bytes_left = length;
     while (bytes_left > 0) {
       bytes_written =
diff --git a/storage/browser/blob/blob_url_loader.cc b/storage/browser/blob/blob_url_loader.cc
index 9361208..580172a 100644
--- a/storage/browser/blob/blob_url_loader.cc
+++ b/storage/browser/blob/blob_url_loader.cc
@@ -164,7 +164,7 @@
 
   // TODO(jam): some of this code can be shared with
   // services/network/url_loader.h
-  client_->OnReceiveResponse(response, base::nullopt, nullptr);
+  client_->OnReceiveResponse(response, nullptr);
   sent_headers_ = true;
 
   if (metadata) {
diff --git a/testing/buildbot/PRESUBMIT.py b/testing/buildbot/PRESUBMIT.py
index f05e1f5..77b079a 100644
--- a/testing/buildbot/PRESUBMIT.py
+++ b/testing/buildbot/PRESUBMIT.py
@@ -42,7 +42,9 @@
   except ImportError:
     messages.append(output_api.PresubmitNotifyResult(
         'Python\'s coverage module is not installed; '
-        'coverage tests in //testing/buildbot are disabled.'))
+        'coverage tests in //testing/buildbot are disabled. '
+        'To fix this on linux try running: '
+        'sudo apt-get install python-coverage'))
 
   messages.extend(input_api.RunTests(commands))
   return messages
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 5a9bf97..7f2e003 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4247,8 +4247,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_browser_tests",
         "swarming": {
@@ -7697,8 +7696,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 82f3baa4..7aeb289 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -683,8 +683,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_browser_tests",
         "swarming": {
@@ -1476,8 +1475,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_browser_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index df14891..54e8ed6 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -1,4 +1,50 @@
 {
+  "Android Go": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "performance_test_suite",
+        "merge": {
+          "args": [
+            "--service-account-file",
+            "/creds/service_accounts/service-account-chromium-perf-histograms.json"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite",
+        "override_compile_targets": [
+          "performance_test_suite"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Android",
+              "pool": "chrome.tests.perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 36000,
+          "ignore_task_failure": false,
+          "io_timeout": 1800,
+          "shards": 14,
+          "upload_test_results": true
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"id\": \"build30-a7--device1\"}, {\"id\": \"build30-a7--device2\"}, {\"id\": \"build30-a7--device3\"}, {\"id\": \"build30-a7--device4\"}, {\"id\": \"build30-a7--device5\"}, {\"id\": \"build30-a7--device6\"}, {\"id\": \"build30-a7--device7\"}, {\"id\": \"build31-a7--device1\"}, {\"id\": \"build31-a7--device2\"}, {\"id\": \"build31-a7--device3\"}, {\"id\": \"build31-a7--device4\"}, {\"id\": \"build31-a7--device5\"}, {\"id\": \"build31-a7--device6\"}, {\"id\": \"build31-a7--device7\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
   "Android Nexus 5X Perf FYI": {
     "isolated_scripts": [
       {
@@ -405,7 +451,6 @@
       {
         "args": [
           "-v",
-          "--xvfb",
           "--browser=release"
         ],
         "isolate_name": "performance_test_suite",
@@ -485,7 +530,6 @@
       {
         "args": [
           "-v",
-          "--xvfb",
           "--browser=reference",
           "--testing=true"
         ],
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index ce795520..f46b991 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -18,8 +18,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_browser_tests",
         "swarming": {
@@ -293,8 +292,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_browser_tests",
         "swarming": {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index e7abb4d64..3f7b2b7 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -31,7 +31,6 @@
     "//testing/buildbot/filters/mash.browser_tests.filter",
     "//testing/buildbot/filters/mojo.fyi.network_browser_tests.filter",
     "//testing/buildbot/filters/browser_tests_cros_asan.filter",
-    "//testing/buildbot/filters/site-per-process.browser_tests.filter",
     "//testing/buildbot/filters/viz.browser_tests.filter",
   ]
 }
@@ -55,14 +54,6 @@
   ]
 }
 
-source_set("interactive_ui_tests_filters") {
-  testonly = true
-
-  data = [
-    "//testing/buildbot/filters/site-per-process.interactive_ui_tests.filter",
-  ]
-}
-
 source_set("unit_tests_filters") {
   testonly = true
 
diff --git a/testing/buildbot/filters/README.md b/testing/buildbot/filters/README.md
index 23e588d5..37e98092 100644
--- a/testing/buildbot/filters/README.md
+++ b/testing/buildbot/filters/README.md
@@ -3,8 +3,8 @@
 ## Summary
 
 This directory contains files that list tests that are not yet ready to run in a
-particular mode. For example - the `site-per-process.browser_tests.filter` file
-lists tests that should be excluded when running `browser_tests` in
+particular mode. For example - the `site-per-process.content_browsertests.filter` file
+lists tests that should be excluded when running `content_browsertests` in
 `--site-per-process` mode.
 
 ## File syntax
diff --git a/testing/buildbot/filters/site-per-process.browser_tests.filter b/testing/buildbot/filters/site-per-process.browser_tests.filter
deleted file mode 100644
index 9ad53d8..0000000
--- a/testing/buildbot/filters/site-per-process.browser_tests.filter
+++ /dev/null
@@ -1,6 +0,0 @@
-# crbug.com/417518: Get tests working with --site-per-process
--BrowserTest.OtherRedirectsDontForkProcess
-
-# crbug.com/671734: WebNavigationApiTest.ServerRedirectSingleProcess from
-# fails with --site-per-process
--WebNavigationApiTest.ServerRedirectSingleProcess
diff --git a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter b/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
deleted file mode 100644
index a81bc837..0000000
--- a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
+++ /dev/null
@@ -1 +0,0 @@
-# List below tests to be excluded from running.
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 9f733fbe..ba88b25 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1959,12 +1959,6 @@
           'shards': 1,
         },
       },
-      'Site Isolation Linux': {
-        'args': [
-          # TODO(kbr): unclear why this isn't specified on "Site Isolation Win".
-          '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.interactive_ui_tests.filter',
-        ],
-      },
       # chromium.mac
       # Unclear why this isn't swarmed.
       'Mac10.10 Tests': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index d21a0b15..f56caa7 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -695,8 +695,7 @@
 
     'site_per_process_browser_tests': {
       'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter'
+        '--site-per-process'
       ],
       'swarming': {
         'shards': 10,
@@ -1457,8 +1456,7 @@
   'site_isolation_chromium_gtests': {
     'site_per_process_browser_tests': {
       'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter',
+        '--site-per-process'
       ],
       'swarming': {
         'shards': 10,
@@ -1561,8 +1559,7 @@
     },
     'browser_tests': {
       'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.browser_tests.filter',
+        '--site-per-process'
       ],
       'swarming': {
         'shards': 10,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 501cee25..7a89491 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3945,6 +3945,24 @@
             ]
         }
     ],
+    "UsePdfCompositorServiceForPrint": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "UsePdfCompositorServiceForPrint",
+                    "enable_features": [
+                        "UsePdfCompositorServiceForPrint"
+                    ]
+                }
+            ]
+        }
+    ],
     "UserActivityEventLogging": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 70d3fee..055d440 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -3,7 +3,6 @@
 
 # Need support for Range.getClientRects() and Range.getBoundingClientRect()
 crbug.com/755750 accessibility/selection-affinity.html [ Failure ]
-crbug.com/755750 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll.html [ Failure ]
 
 ## Reverse hosting of editable block
 crbug.com/707656 editing/input/scroll-viewport-page-up-down.html [ Failure ]
@@ -94,7 +93,7 @@
 crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ]
 crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Pass Timeout ]
+crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
@@ -117,7 +116,7 @@
 crbug.com/591099 compositing/overflow/nested-border-radius-clipping.html [ Failure ]
 crbug.com/591099 compositing/overflow/overflow-scroll-with-local-image-background.html [ Failure ]
 crbug.com/591099 compositing/overflow/scrolling-content-clip-to-viewport.html [ Failure ]
-crbug.com/591099 compositing/overflow/universal-accelerated-overflow-scroll.html [ Pass Timeout ]
+crbug.com/591099 compositing/overflow/universal-accelerated-overflow-scroll.html [ Timeout ]
 crbug.com/591099 compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure ]
 crbug.com/591099 compositing/rtl/rtl-and-writing-mode-scrolling.html [ Failure ]
 crbug.com/591099 compositing/scrollbars/nested-overlay-scrollbars.html [ Failure ]
@@ -189,7 +188,7 @@
 crbug.com/591099 editing/execCommand/findString.html [ Failure ]
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs-in-pre.html [ Failure ]
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs.html [ Failure ]
-crbug.com/591099 editing/execCommand/query-format-block.html [ Pass Timeout ]
+crbug.com/591099 editing/execCommand/query-format-block.html [ Timeout ]
 crbug.com/591099 editing/execCommand/remove-list-from-range-selection.html [ Failure ]
 crbug.com/591099 editing/inserting/4875189-1.html [ Failure ]
 crbug.com/591099 editing/inserting/4959067.html [ Failure ]
@@ -243,7 +242,6 @@
 crbug.com/591099 editing/selection/paragraph-granularity.html [ Failure ]
 crbug.com/591099 editing/selection/programmatic-selection-on-mac-is-directionless.html [ Timeout ]
 crbug.com/591099 editing/selection/select-bidi-run.html [ Failure ]
-crbug.com/714962 editing/selection/select-from-textfield-outwards.html [ Failure ]
 crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-ltr-2.html [ Failure ]
 crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-ltr.html [ Failure ]
 crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-rtl-2.html [ Failure ]
@@ -329,7 +327,6 @@
 crbug.com/824918 external/wpt/css/css-multicol/multicol-rule-dotted-000.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-position/position-sticky-overflow-padding.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-position/position-sticky-writing-modes.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-pseudo/first-letter-003.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-rhythm/line-height-step-basic-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-rhythm/line-height-step-boundary-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-rhythm/line-height-step-dynamic-001.html [ Failure ]
@@ -450,6 +447,8 @@
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-017.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-019.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/td-different-subpixel-padding-in-same-row.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ]
@@ -685,7 +684,6 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-024.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-026.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ]
-crbug.com/714962 external/wpt/css/cssom-view/DOMRectList.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/cssom-getClientRects-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-003.html [ Failure ]
@@ -745,7 +743,7 @@
 crbug.com/591099 external/wpt/editing/run/removeformat.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/subscript.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/editing/run/superscript.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/underline.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-cseucpkdfmtjapanese.html [ Timeout ]
@@ -878,7 +876,6 @@
 crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html [ Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html [ Failure ]
-crbug.com/714962 external/wpt/pointerevents/pointerevent_touch-action-mouse-manual.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html [ Failure ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
 crbug.com/591099 external/wpt/quirks/table-cell-width-calculation.html [ Pass ]
@@ -892,7 +889,7 @@
 crbug.com/591099 external/wpt/selection/addRange-00.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-04.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-12.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/selection/addRange-16.html [ Timeout ]
+crbug.com/591099 external/wpt/selection/addRange-16.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-24.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-28.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-32.html [ Timeout ]
@@ -1021,7 +1018,7 @@
 crbug.com/591099 fast/box-shadow/box-shadow.html [ Failure ]
 crbug.com/591099 fast/box-shadow/inset-subpixel.html [ Failure ]
 crbug.com/591099 fast/box-shadow/inset.html [ Failure ]
-crbug.com/591099 fast/box-sizing/replaced.html [ Failure ]
+crbug.com/591099 fast/box-sizing/replaced.html [ Failure Pass ]
 crbug.com/591099 fast/clip/overflow-border-radius-combinations.html [ Failure ]
 crbug.com/591099 fast/clip/overflow-border-radius-composited-parent.html [ Failure ]
 crbug.com/591099 fast/clip/overflow-border-radius-composited.html [ Failure ]
@@ -1239,23 +1236,15 @@
 crbug.com/591099 fast/dom/HTMLMeterElement/meter-boundary-values.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLMeterElement/meter-optimums.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element.html [ Failure ]
-crbug.com/714962 fast/dom/Range/collapsed-range-bounding-client-rect.html [ Failure ]
-crbug.com/714962 fast/dom/Range/get-bounding-client-rect-empty-and-non-empty.html [ Timeout ]
-crbug.com/714962 fast/dom/Range/getBoundingClientRect-getClientRects-relative-to-viewport.html [ Failure ]
 crbug.com/714962 fast/dom/Range/getBoundingClientRect-linebreak-character.html [ Failure ]
-crbug.com/714962 fast/dom/Range/getBoundingClientRect.html [ Failure ]
-crbug.com/714962 fast/dom/Range/getClientRects-character.html [ Failure ]
-crbug.com/591099 fast/dom/Range/getClientRects-leading-trailing-whitespaces.html [ Failure ]
-crbug.com/591099 fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Failure Timeout ]
+crbug.com/591099 fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Timeout ]
 crbug.com/591099 fast/dom/Window/window-lookup-precedence.html [ Timeout ]
 crbug.com/591099 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
-crbug.com/714962 fast/dom/anchor-without-content.html [ Failure ]
 crbug.com/591099 fast/dom/clone-node-dynamic-style.html [ Failure ]
 crbug.com/591099 fast/dom/domstring-attribute-reflection.html [ Timeout ]
 crbug.com/591099 fast/dom/element-attribute-js-null.html [ Timeout ]
 crbug.com/714962 fast/dom/elementFromPoint-relative-to-viewport.html [ Failure ]
 crbug.com/714962 fast/dom/elementsFromPoint/elementsFromPoint-inline.html [ Failure ]
-crbug.com/714962 fast/dom/empty-anchor-in-overflow-scroller.html [ Failure ]
 crbug.com/714962 fast/dom/inert/inert-inlines.html [ Failure ]
 crbug.com/591099 fast/dom/inner-text-first-letter.html [ Failure ]
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
@@ -1275,8 +1264,7 @@
 crbug.com/714962 fast/events/drag-in-frames.html [ Failure ]
 crbug.com/714962 fast/events/event-on-culled_inline.html [ Failure ]
 crbug.com/591099 fast/events/keyboardevent-getModifierState.html [ Timeout ]
-crbug.com/591099 fast/events/menu-key-context-menu-document-pinch-zoom.html [ Failure ]
-crbug.com/714962 fast/events/middleClickAutoscroll-latching.html [ Pass Timeout ]
+crbug.com/714962 fast/events/middleClickAutoscroll-latching.html [ Timeout ]
 crbug.com/714962 fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure Pass ]
 crbug.com/591099 fast/events/mouse-event-buttons-attribute.html [ Timeout ]
 crbug.com/591099 fast/events/mouse-relative-position.html [ Failure ]
@@ -1284,7 +1272,7 @@
 crbug.com/591099 fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 fast/events/pointer-events-2.html [ Failure ]
 crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ]
-crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture.html [ Pass Timeout ]
+crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture.html [ Timeout ]
 crbug.com/591099 fast/events/pointerevents/mouse-pointer-event-properties.html [ Timeout ]
 crbug.com/591099 fast/events/pointerevents/mouse-pointer-preventdefault.html [ Timeout ]
 crbug.com/591099 fast/events/pointerevents/multi-pointer-preventdefault.html [ Pass Timeout ]
@@ -1296,7 +1284,7 @@
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
-crbug.com/591099 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/calendar-picker-mouse-operations.html [ Failure ]
 crbug.com/591099 fast/forms/calendar-picker/month-picker-key-operations.html [ Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/month-picker-mouse-operations.html [ Failure ]
@@ -1472,8 +1460,6 @@
 crbug.com/591099 fast/scrolling/jquery-rtl-scroll-type.html [ Failure ]
 crbug.com/591099 fast/scrolling/scrollable-area-frame-overflow-hidden.html [ Failure ]
 crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Pass ]
-crbug.com/714962 fast/scrolling/scrollbar-tickmarks-styled-after-onload.html [ Failure ]
-crbug.com/714962 fast/scrolling/scrollbar-tickmarks-styled.html [ Failure ]
 crbug.com/591099 fast/selectors/038.html [ Failure ]
 crbug.com/591099 fast/selectors/166.html [ Failure ]
 crbug.com/591099 fast/selectors/167.html [ Failure ]
@@ -1542,25 +1528,9 @@
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-rounded-boxes-001.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-rounded-boxes-002.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-rounded-inset.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-date.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-fully-aligned-horizontally.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-fully-aligned-vertically.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-iframe-nested.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-iframe-no-focusable-content.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-iframe-no-scrollable-content.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html [ Failure ]
-crbug.com/591099 fast/spatial-navigation/snav-iframe-with-outside-focusable-element.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-input.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-multiple-select.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-radio-group.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-radio.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-single-select-list.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-single-select.html [ Timeout ]
 crbug.com/591099 fast/spatial-navigation/snav-stay-in-overflow-div.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-table-traversal.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-textarea.html [ Failure ]
-crbug.com/714962 fast/spatial-navigation/snav-tiny-table-traversal.html [ Failure ]
-crbug.com/591099 fast/spatial-navigation/snav-use-visual-viewport.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/computedstylemargin.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/inline-block-with-padding.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
@@ -1701,19 +1671,14 @@
 crbug.com/591099 fast/text/emphasis-overlap.html [ Failure ]
 crbug.com/591099 fast/text/find-kana.html [ Timeout ]
 crbug.com/714962 fast/text/get-client-rects-grapheme.html [ Failure ]
-crbug.com/714962 fast/text/glyph-reordering.html [ Failure ]
 crbug.com/591099 fast/text/hide-atomic-inlines-after-ellipsis.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-002.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-003.html [ Failure ]
 crbug.com/591099 fast/text/international/combining-marks-position.html [ Failure ]
 crbug.com/714962 fast/text/international/hindi-whitespace.html [ Failure ]
-crbug.com/714962 fast/text/international/iso-8859-8.html [ Failure ]
-crbug.com/714962 fast/text/international/rtl-selection-rect-with-fallback.html [ Failure ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
 crbug.com/591099 fast/text/international/text-combine-image-test.html [ Failure ]
 crbug.com/591099 fast/text/large-text-composed-char.html [ Timeout ]
-crbug.com/714962 fast/text/line-break-after-inline-latin1.html [ Failure ]
-crbug.com/714962 fast/text/multiglyph-characters.html [ Failure ]
 crbug.com/591099 fast/text/place-ellipsis-in-inline-block-adjacent-float-2.html [ Failure ]
 crbug.com/591099 fast/text/place-ellipsis-in-inline-block-adjacent-float.html [ Failure ]
 crbug.com/591099 fast/text/place-ellipsis-in-inline-blocks-2.html [ Failure ]
@@ -1745,7 +1710,6 @@
 crbug.com/591099 fast/text/selection/selection-rect-rounding.html [ Failure ]
 crbug.com/591099 fast/text/selection/selection-with-inline-padding.html [ Failure ]
 crbug.com/714962 fast/text/selection/shaping-selection-rect.html [ Failure ]
-crbug.com/714962 fast/text/text-range-bounds.html [ Failure ]
 crbug.com/714962 fast/text/transform-text-first-line-capitalize.html [ Failure ]
 crbug.com/714962 fast/text/transform-text-first-line-lowercase.html [ Failure ]
 crbug.com/714962 fast/text/transform-text-first-line.html [ Failure ]
@@ -1775,7 +1739,6 @@
 crbug.com/591099 fast/writing-mode/fieldsets.html [ Failure ]
 crbug.com/714962 fast/writing-mode/flipped-blocks-hit-test-line-edges.html [ Failure ]
 crbug.com/591099 fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Failure ]
-crbug.com/714962 fast/writing-mode/flipped-blocks-text-map-local-to-container.html [ Failure ]
 crbug.com/714962 fast/writing-mode/japanese-lr-selection.html [ Failure ]
 crbug.com/714962 fast/writing-mode/japanese-rl-selection.html [ Failure ]
 crbug.com/591099 fast/writing-mode/japanese-ruby-vertical-lr.html [ Failure ]
@@ -1801,7 +1764,7 @@
 crbug.com/591099 fullscreen/full-screen-element-stack.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-iframe-not-allowed.html [ Failure ]
 crbug.com/591099 fullscreen/full-screen-remove-ancestor-after.html [ Crash Pass ]
-crbug.com/591099 fullscreen/full-screen-ruleset-crash.html [ Crash Pass ]
+crbug.com/591099 fullscreen/full-screen-ruleset-crash.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-twice-newapi.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-with-css-reference-filter.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-with-flex-item.html [ Crash ]
@@ -1837,10 +1800,7 @@
 crbug.com/591099 http/tests/devtools/editor/text-editor-block-indent.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
-crbug.com/714962 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/editor/text-editor-formatter.js [ Timeout ]
-crbug.com/714962 http/tests/devtools/editor/text-editor-indent-autodetection.js [ Timeout ]
-crbug.com/714962 http/tests/devtools/editor/text-editor-reveal-line.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
@@ -1876,7 +1836,7 @@
 crbug.com/591099 http/tests/security/contentSecurityPolicy/source-list-parsing-04.html [ Failure ]
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-appcache.html [ Crash Failure ]
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
 crbug.com/591099 http/tests/security/shape-image-cors-allow-origin.html [ Failure ]
 crbug.com/591099 http/tests/security/shape-image-cors-data-url.html [ Failure ]
 crbug.com/591099 http/tests/security/shape-image-cors-same-origin.html [ Failure ]
@@ -2429,8 +2389,7 @@
 crbug.com/591099 virtual/gpu-rasterization/images/percent-height-image.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/rendering-broken-block-flow-images.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/rendering-broken-images.html [ Failure ]
-crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Pass ]
-crbug.com/714962 virtual/gpu/fast/canvas/canvas-css-clip-path.html [ Failure ]
+crbug.com/714962 virtual/gpu/fast/canvas/canvas-css-clip-path.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ]
 crbug.com/591099 virtual/incremental-shadow-dom/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
@@ -2465,7 +2424,6 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
-crbug.com/714962 virtual/mouseevent_fractional/fast/events/wheel/wheelevent-basic.html [ Failure Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html [ Failure Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Timeout ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 8692795..e03ad93 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -450,7 +450,6 @@
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/fieldsets.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-hit-test-line-edges.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-text-map-local-to-container.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-lr-selection.html [ Failure ]
 crbug.com/714962 [ Mac Win ] virtual/layout_ng/fast/writing-mode/japanese-lr-text.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-rl-selection.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
index 8ab0363..0d4f6c0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
@@ -13,8 +13,7 @@
 <script>
 'use strict';
 
-// FIXME: animation-direction is list-valued. Run list-valued tests here too.
-runPropertyTests('animation-direction', [
+runListValuedPropertyTests('animation-direction', [
   { syntax: 'normal' },
   { syntax: 'reverse' },
   { syntax: 'alternate-reverse' },
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/background-image.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/background-image.html
index d584a0f..b3ddded 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/background-image.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/background-image.html
@@ -13,8 +13,7 @@
 <script>
 'use strict';
 
-// FIXME: background-image is list-valued. Run list-valued tests here too.
-runPropertyTests('background-image', [
+runListValuedPropertyTests('background-image', [
   { syntax: 'none' },
   { syntax: '<image>' },
 ]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/column-width.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/column-width.html
new file mode 100644
index 0000000..97a00ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/column-width.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymapreadonly-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#reify-stylevalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-width', [
+  { syntax: 'auto' },
+  {
+    syntax: '<length>',
+    specified: assert_is_equal_with_range_handling
+  },
+]);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/mask-image.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/mask-image.html
index f306fdd..aa858d2e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/mask-image.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/mask-image.html
@@ -13,8 +13,7 @@
 <script>
 'use strict';
 
-// FIXME: mask-image is list-valued. Run list-valued tests here too.
-runPropertyTests('mask-image', [
+runListValuedPropertyTests('mask-image', [
   { syntax: 'none' },
   { syntax: '<image>' },
 ]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
index 2c20c05..bf2b217 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
@@ -378,6 +378,12 @@
   }
 }
 
+// Same as runPropertyTests but for list-valued properties.
+function runListValuedPropertyTests(propertyName, testCases) {
+  // TODO(https://crbug.com/545318): Run list-valued tests as well.
+  runPropertyTests(propertyName, testCases);
+}
+
 // Check that |propertyName| doesn't "support" examples in |testExamples|.
 // |testExamples| is a list of CSS string values. An "unsupported" value
 // doesn't have a corresponding Typed OM representation. It normalizes as
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html
index c17e717..c0eb09d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html
@@ -12,8 +12,7 @@
 <script>
 'use strict';
 
-// FIXME: transition-duration is list-valued. Run list-valued tests here too.
-runPropertyTests('transition-duration', [
+runListValuedPropertyTests('transition-duration', [
   { syntax: '<time>' },
 ]);
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
index ab8f772..86afc68d 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
@@ -12,137 +12,281 @@
 pointermove of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousemove is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 pointerdown of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousedown is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 pointerup of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mouseup is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
  *** Touch events inside iframe ***
 pointerdown of touch is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchstart is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 pointermove of touch is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchmove is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 pointerup of touch is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchend is received:
 clientX = 150
 clientY = 100
+pageX = 175
+pageY = 200
+screenX = 200
+screenY = 200
 
 ===== scrollX=40, scrollY=140, zoomFactor=1
  *** Mouse events inside iframe ***
 pointermove of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousemove is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 pointerdown of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousedown is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 pointerup of mouse is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mouseup is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
  *** Touch events inside iframe ***
 pointerdown of touch is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchstart is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 pointermove of touch is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchmove is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 pointerup of touch is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchend is received:
 clientX = 150
 clientY = 100
+pageX = 190
+pageY = 240
+screenX = 200
+screenY = 200
 
 ===== scrollX=40, scrollY=140, zoomFactor=2
  *** Mouse events inside iframe ***
 pointermove of mouse is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousemove is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 pointerdown of mouse is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mousedown is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 pointerup of mouse is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 mouseup is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
  *** Touch events inside iframe ***
 pointerdown of touch is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchstart is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 pointermove of touch is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchmove is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 pointerup of touch is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 view.name = innerFrame
 touchend is received:
 clientX = 50
 clientY = 0
+pageX = 90
+pageY = 140
+screenX = 200
+screenY = 200
 
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
index 222b194..7c0b8fe 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
@@ -34,7 +34,11 @@
 
 var attributes = [
     'clientX',
-    'clientY'
+    'clientY',
+    'pageX',
+    'pageY',
+    'screenX',
+    'screenY'
 ];
 
 document.events = [];
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSettings.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSettings.html
index 3d58832..de73253f 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSettings.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSettings.html
@@ -26,6 +26,12 @@
     assert_greater_than(Object.keys(settings).length, 0);
     assert_true('deviceId' in settings,
                 'Device ID missing: ' + JSON.stringify(settings));
+    assert_true('echoCancellation' in settings,
+                'Echo cancellation missing: ' + JSON.stringify(settings));
+    assert_true('autoGainControl' in settings,
+                'Automatic gain control missing: ' + JSON.stringify(settings));
+    assert_true('noiseSuppression' in settings,
+                'Noise suppression missing: ' + JSON.stringify(settings));
   });
 }, 'An audio track returns the expected variables');
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html
index fc54586..d07fe06 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html
@@ -1,14 +1,14 @@
 <html>
 <body>
-The navigation should succeed. This text shouldn't appear.
+The navigation should fail. This text should be visible.
 <script>
 window.onload = function()
 {
     try {
         top.location = "http://localhost:8000/security/frameNavigation/resources/navigation-changed-iframe.html";
-        top.postMessage("PASS", "*");
-    } catch(e) {
         top.postMessage("FAIL", "*");
+    } catch(e) {
+        top.postMessage("PASS", "*");
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-user-gesture-in-parent-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-user-gesture-in-parent-expected.txt
index 4ec5fe0..ee18088 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-user-gesture-in-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-user-gesture-in-parent-expected.txt
@@ -1,2 +1,6 @@
-localhost
-PASSED: Navigation succeeded.
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+The navigation should fail. This text should be visible.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture-expected.txt
index 5a29641..3558992 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture-expected.txt
@@ -1,3 +1,8 @@
-CONSOLE WARNING: line 8: Frame with URL 'http://localhost:8000/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html' attempted to navigate its top-level window with URL 'http://127.0.0.1:8000/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture.html'. Navigating the top-level window from a cross-origin iframe will soon require that the iframe has received a user gesture. See https://www.chromestatus.com/features/5851021045661696.
-localhost
-PASSED: Navigation succeeded.
+CONSOLE ERROR: line 8: Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://127.0.0.1:8000/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture.html' from frame with URL 'http://localhost:8000/security/frameNavigation/resources/iframe-that-performs-top-navigation-without-user-gesture.html'. The frame attempting navigation is targeting its top-level window, but is neither same-origin with its target nor has it received a user gesture. See https://www.chromestatus.com/features/5851021045661696.
+
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+The navigation should fail. This text should be visible.
diff --git a/third_party/WebKit/LayoutTests/media/controls/immersive-cast-button.html b/third_party/WebKit/LayoutTests/media/controls/immersive-cast-button.html
new file mode 100644
index 0000000..53cf793
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/controls/immersive-cast-button.html
@@ -0,0 +1,26 @@
+<!DOCTYPe html>
+<title>Test that the cast button does not show up in immersive mode</title>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<script src='../media-controls.js'></script>
+<body></body>
+<script>
+async_test(t => {
+  var old_immersive = internals.settings.immersiveModeEnabled;
+  internals.settings.setImmersiveModeEnabled(true);
+  t.add_cleanup(() => {
+    internals.settings.setImmersiveModeEnabled(old_immersive);
+  });
+
+  var video = document.createElement('video');
+  video.controls = true;
+  document.body.appendChild(video);
+  video.src = '../content/test.ogv';
+  internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true);
+
+  video.addEventListener('canplaythrough', t.step_func_done(e => {
+    assert_equals(castButton(video).style.display, 'none');
+    assert_not_equals(mediaControlsButton(video, 'panel').style.display, 'none');
+  }));
+});
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index ffcb6d35..5aa92c6 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -266,7 +266,6 @@
           BlinkGC::kEagerSweeping, BlinkGC::kForcedGC);
 
       // Forces a precise GC at the end of the current event loop.
-      CHECK(!current_thread_state->IsInGC());
       current_thread_state->SetGCState(ThreadState::kFullGCScheduled);
     }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index 61e1601..14f90ba 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -806,5 +806,9 @@
 STATIC_ASSERT_ENUM(WebSettings::kV8CacheOptionsDefault, kV8CacheOptionsDefault);
 STATIC_ASSERT_ENUM(WebSettings::kV8CacheOptionsNone, kV8CacheOptionsNone);
 STATIC_ASSERT_ENUM(WebSettings::kV8CacheOptionsCode, kV8CacheOptionsCode);
+STATIC_ASSERT_ENUM(WebSettings::kV8CacheOptionsCodeWithoutHeatCheck,
+                   kV8CacheOptionsCodeWithoutHeatCheck);
+STATIC_ASSERT_ENUM(WebSettings::kV8CacheOptionsFullCodeWithoutHeatCheck,
+                   kV8CacheOptionsFullCodeWithoutHeatCheck);
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp
index d16867d..31c54d1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp
@@ -31,7 +31,7 @@
 
   scoped_refptr<SerializedScriptValue> serializedScriptValue =
       SerializedScriptValue::Create(
-          reinterpret_cast<const char*>(wire_data.data()), wire_data.length());
+          reinterpret_cast<const char*>(wire_data.data()), wire_data.size());
   v8::Local<v8::Value> deserialized =
       serializedScriptValue->Deserialize(scope.GetIsolate());
   EXPECT_TRUE(deserialized->IsTrue());
diff --git a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
index 9add0d0..69e79a3 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
+++ b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
@@ -151,7 +151,7 @@
                                        non_throwable_exception_state);
   base::span<const uint8_t> ssv_wire_data = serialized_value->GetWireData();
   DCHECK(wire_bytes->IsEmpty());
-  wire_bytes->Append(ssv_wire_data.data(), ssv_wire_data.length());
+  wire_bytes->Append(ssv_wire_data.data(), ssv_wire_data.size());
 
   // Sanity check that the serialization header has not changed, as the tests
   // that use this method rely on the header format.
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index 4379fc9..492ed6ee 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -906,19 +906,19 @@
 
   bool reversed = playback_rate_ < 0;
 
-  // TODO(crbug.com/791086): Make StartAnimationOnCompositor use WTF::Optional.
-  double start_time = NullValue();
+  WTF::Optional<double> start_time = WTF::nullopt;
   double time_offset = 0;
   if (start_time_) {
     start_time = TimelineInternal()->ZeroTime() + start_time_.value();
     if (reversed)
-      start_time -= EffectEnd() / fabs(playback_rate_);
+      start_time = start_time.value() - (EffectEnd() / fabs(playback_rate_));
   } else {
     time_offset =
         reversed ? EffectEnd() - CurrentTimeInternal() : CurrentTimeInternal();
     time_offset = time_offset / fabs(playback_rate_);
   }
 
+  DCHECK(!start_time || !IsNull(start_time.value()));
   DCHECK_NE(compositor_group_, 0);
   ToKeyframeEffect(content_.Get())
       ->StartAnimationOnCompositor(compositor_group_, start_time, time_offset,
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
index 3d3e1ff4..1813376 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -379,7 +379,7 @@
 void CompositorAnimations::StartAnimationOnCompositor(
     const Element& element,
     int group,
-    double start_time,
+    WTF::Optional<double> start_time,
     double time_offset,
     const Timing& timing,
     const Animation* animation,
@@ -573,7 +573,7 @@
 void CompositorAnimations::GetAnimationOnCompositor(
     const Timing& timing,
     int group,
-    double start_time,
+    WTF::Optional<double> start_time,
     double time_offset,
     const KeyframeEffectModelBase& effect,
     Vector<std::unique_ptr<CompositorKeyframeModel>>& keyframe_models,
@@ -644,8 +644,8 @@
     std::unique_ptr<CompositorKeyframeModel> keyframe_model =
         CompositorKeyframeModel::Create(*curve, target_property, group, 0);
 
-    if (!std::isnan(start_time))
-      keyframe_model->SetStartTime(start_time);
+    if (start_time)
+      keyframe_model->SetStartTime(start_time.value());
 
     keyframe_model->SetIterations(compositor_timing.adjusted_iteration_count);
     keyframe_model->SetIterationStart(compositor_timing.iteration_start);
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.h b/third_party/WebKit/Source/core/animation/CompositorAnimations.h
index 1919e330..e0aac31 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimations.h
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.h
@@ -101,7 +101,7 @@
                                                        const EffectModel&);
   static void StartAnimationOnCompositor(const Element&,
                                          int group,
-                                         double start_time,
+                                         WTF::Optional<double> start_time,
                                          double time_offset,
                                          const Timing&,
                                          const Animation*,
@@ -137,7 +137,7 @@
   static void GetAnimationOnCompositor(
       const Timing&,
       int group,
-      double start_time,
+      WTF::Optional<double> start_time,
       double time_offset,
       const KeyframeEffectModelBase&,
       Vector<std::unique_ptr<CompositorKeyframeModel>>& animations,
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
index b3c4cf4..28ad8ee 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -153,9 +153,9 @@
       StringKeyframeEffectModel& effect,
       Vector<std::unique_ptr<CompositorKeyframeModel>>& keyframe_models,
       double animation_playback_rate) {
-    CompositorAnimations::GetAnimationOnCompositor(
-        timing, 0, std::numeric_limits<double>::quiet_NaN(), 0, effect,
-        keyframe_models, animation_playback_rate);
+    CompositorAnimations::GetAnimationOnCompositor(timing, 0, WTF::nullopt, 0,
+                                                   effect, keyframe_models,
+                                                   animation_playback_rate);
   }
 
   bool DuplicateSingleKeyframeAndTestIsCandidateOnResult(
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
index df1ac38..72e9df8b 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
@@ -232,7 +232,7 @@
 
 void KeyframeEffect::StartAnimationOnCompositor(
     int group,
-    double start_time,
+    WTF::Optional<double> start_time,
     double current_time,
     double animation_playback_rate,
     CompositorAnimation* compositor_animation) {
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffect.h b/third_party/WebKit/Source/core/animation/KeyframeEffect.h
index 2bfc88b..1d9b41d 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffect.h
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffect.h
@@ -101,7 +101,7 @@
       double animation_playback_rate) const;
   // Must only be called once.
   void StartAnimationOnCompositor(int group,
-                                  double start_time,
+                                  WTF::Optional<double> start_time,
                                   double time_offset,
                                   double animation_playback_rate,
                                   CompositorAnimation* = nullptr);
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index be18958..375389ba 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -3203,6 +3203,8 @@
       computed_style_custom_functions: ["setter"],
       converter: "ConvertComputedLength<float>",
       custom_apply_functions_all: true,
+      keywords: ["auto"],
+      typedom_types: ["Keyword", "Length"],
     },
     {
       name: "-webkit-highlight",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 29e4639..7463c0d 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -191,15 +191,6 @@
     },
     // These properties only have generated storage, and their methods are handwritten in ComputedStyle.
     {
-      name: "EmptyState",
-      field_template: "primitive",
-      default_value: "false",
-      type_name: "bool",
-      custom_copy: true,
-      custom_compare: true,
-      computed_style_custom_functions: ["setter"],
-    },
-    {
       name: "StyleType",
       field_template: "primitive",
       field_size: 6,
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
index 949ffe1..01ee4cb1 100644
--- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -789,13 +789,8 @@
           }
         }
       }
-      if (mode_ == kResolvingStyle) {
+      if (mode_ == kResolvingStyle)
         element.SetStyleAffectedByEmpty();
-        if (context.in_rightmost_compound)
-          element_style_->SetEmptyState(result);
-        else if (element.GetComputedStyle())
-          element.MutableComputedStyle()->SetEmptyState(result);
-      }
       return result;
     }
     case CSSSelector::kPseudoFirstChild:
diff --git a/third_party/WebKit/Source/core/css/StyleEngineTest.cpp b/third_party/WebKit/Source/core/css/StyleEngineTest.cpp
index 726afca..57a79a2 100644
--- a/third_party/WebKit/Source/core/css/StyleEngineTest.cpp
+++ b/third_party/WebKit/Source/core/css/StyleEngineTest.cpp
@@ -19,6 +19,7 @@
 #include "core/frame/FrameTestHelpers.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/html/HTMLElement.h"
+#include "core/html/HTMLSpanElement.h"
 #include "core/html/HTMLStyleElement.h"
 #include "core/testing/DummyPageHolder.h"
 #include "platform/geometry/FloatSize.h"
@@ -1251,4 +1252,156 @@
   EXPECT_TRUE(GetStyleEngine().NeedsActiveStyleUpdate());
 }
 
+TEST_F(StyleEngineTest, EmptyPseudo_RemoveLast) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty>Text</div>
+    <span></span>
+    <div id=t2 class=empty><span></span></div>
+    <span></span>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  Element* t1 = GetDocument().getElementById("t1");
+  t1->firstChild()->remove();
+  EXPECT_TRUE(t1->NeedsStyleInvalidation());
+
+  Element* t2 = GetDocument().getElementById("t2");
+  t2->firstChild()->remove();
+  EXPECT_TRUE(t2->NeedsStyleInvalidation());
+}
+
+TEST_F(StyleEngineTest, EmptyPseudo_RemoveNotLast) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty>Text<span></span></div>
+    <span></span>
+    <div id=t2 class=empty><span></span><span></span></div>
+    <span></span>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  Element* t1 = GetDocument().getElementById("t1");
+  t1->firstChild()->remove();
+  EXPECT_FALSE(t1->NeedsStyleInvalidation());
+
+  Element* t2 = GetDocument().getElementById("t2");
+  t2->firstChild()->remove();
+  EXPECT_FALSE(t2->NeedsStyleInvalidation());
+}
+
+TEST_F(StyleEngineTest, EmptyPseudo_InsertFirst) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty></div>
+    <span></span>
+    <div id=t2 class=empty></div>
+    <span></span>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  Element* t1 = GetDocument().getElementById("t1");
+  t1->appendChild(Text::Create(GetDocument(), "Text"));
+  EXPECT_TRUE(t1->NeedsStyleInvalidation());
+
+  Element* t2 = GetDocument().getElementById("t2");
+  t2->appendChild(HTMLSpanElement::Create(GetDocument()));
+  EXPECT_TRUE(t2->NeedsStyleInvalidation());
+}
+
+TEST_F(StyleEngineTest, EmptyPseudo_InsertNotFirst) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty>Text</div>
+    <span></span>
+    <div id=t2 class=empty><span></span></div>
+    <span></span>
+  )HTML");
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  Element* t1 = GetDocument().getElementById("t1");
+  t1->appendChild(Text::Create(GetDocument(), "Text"));
+  EXPECT_FALSE(t1->NeedsStyleInvalidation());
+
+  Element* t2 = GetDocument().getElementById("t2");
+  t2->appendChild(HTMLSpanElement::Create(GetDocument()));
+  EXPECT_FALSE(t2->NeedsStyleInvalidation());
+}
+
+TEST_F(StyleEngineTest, EmptyPseudo_ModifyTextData_SingleNode) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty>Text</div>
+    <span></span>
+    <div id=t2 class=empty></div>
+    <span></span>
+    <div id=t3 class=empty>Text</div>
+    <span></span>
+  )HTML");
+
+  Element* t1 = GetDocument().getElementById("t1");
+  Element* t2 = GetDocument().getElementById("t2");
+  Element* t3 = GetDocument().getElementById("t3");
+
+  t2->appendChild(Text::Create(GetDocument(), ""));
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  ToText(t1->firstChild())->setData("");
+  EXPECT_TRUE(t1->NeedsStyleInvalidation());
+
+  ToText(t2->firstChild())->setData("Text");
+  EXPECT_TRUE(t2->NeedsStyleInvalidation());
+
+  // This is not optimal. We do not detect that we change text to/from
+  // non-empty string.
+  ToText(t3->firstChild())->setData("NewText");
+  EXPECT_TRUE(t3->NeedsStyleInvalidation());
+}
+
+TEST_F(StyleEngineTest, EmptyPseudo_ModifyTextData_HasSiblings) {
+  GetDocument().body()->SetInnerHTMLFromString(R"HTML(
+    <style>
+      .empty:empty + span { color: purple }
+    </style>
+    <div id=t1 class=empty>Text<span></span></div>
+    <span></span>
+    <div id=t2 class=empty><span></span></div>
+    <span></span>
+    <div id=t3 class=empty>Text<span></span></div>
+    <span></span>
+  )HTML");
+
+  Element* t1 = GetDocument().getElementById("t1");
+  Element* t2 = GetDocument().getElementById("t2");
+  Element* t3 = GetDocument().getElementById("t3");
+
+  t2->appendChild(Text::Create(GetDocument(), ""));
+
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  ToText(t1->firstChild())->setData("");
+  EXPECT_FALSE(t1->NeedsStyleInvalidation());
+
+  ToText(t2->lastChild())->setData("Text");
+  EXPECT_FALSE(t2->NeedsStyleInvalidation());
+
+  ToText(t3->firstChild())->setData("NewText");
+  EXPECT_FALSE(t3->NeedsStyleInvalidation());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index e0d8f4b2..0796159 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2198,7 +2198,7 @@
   DCHECK(change >= kIndependentInherit || NeedsStyleRecalc());
   DCHECK(ParentComputedStyle());
 
-  scoped_refptr<ComputedStyle> old_style = MutableComputedStyle();
+  scoped_refptr<const ComputedStyle> old_style = GetComputedStyle();
 
   // When propagating inherited changes, we don't need to do a full style recalc
   // if the only changed properties are independent. In this case, we can simply
@@ -2683,22 +2683,41 @@
   return false;
 }
 
-void Element::CheckForEmptyStyleChange() {
-  const ComputedStyle* style = GetComputedStyle();
+namespace {
 
-  if (!style && !StyleAffectedByEmpty())
-    return;
+bool HasSiblingsForNonEmpty(const Node* sibling,
+                            Node* (*next_func)(const Node&)) {
+  for (; sibling; sibling = next_func(*sibling)) {
+    if (sibling->IsElementNode())
+      return true;
+    if (sibling->IsTextNode() && !ToText(sibling)->data().IsEmpty())
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+void Element::CheckForEmptyStyleChange(const Node* node_before_change,
+                                       const Node* node_after_change) {
   if (!InActiveDocument())
     return;
-  if (!style ||
-      (StyleAffectedByEmpty() && (!style->EmptyState() || HasChildren())))
-    PseudoStateChanged(CSSSelector::kPseudoEmpty);
+  if (!StyleAffectedByEmpty())
+    return;
+  if (HasSiblingsForNonEmpty(node_before_change,
+                             NodeTraversal::PreviousSibling) ||
+      HasSiblingsForNonEmpty(node_after_change, NodeTraversal::NextSibling)) {
+    return;
+  }
+  PseudoStateChanged(CSSSelector::kPseudoEmpty);
 }
 
 void Element::ChildrenChanged(const ChildrenChange& change) {
   ContainerNode::ChildrenChanged(change);
 
-  CheckForEmptyStyleChange();
+  CheckForEmptyStyleChange(change.sibling_before_change,
+                           change.sibling_after_change);
+
   if (!change.by_parser && change.IsChildElementChange())
     CheckForSiblingStyleChanges(
         change.type == kElementRemoved ? kSiblingElementRemoved
@@ -2713,7 +2732,7 @@
 
 void Element::FinishParsingChildren() {
   SetIsFinishedParsingChildren(true);
-  CheckForEmptyStyleChange();
+  CheckForEmptyStyleChange(this, this);
   CheckForSiblingStyleChanges(kFinishedParsingChildren, nullptr, lastChild(),
                               nullptr);
 }
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index f6440cc..47e6ad8 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -963,7 +963,8 @@
 
   void RebuildPseudoElementLayoutTree(PseudoId, WhitespaceAttacher&);
   void RebuildShadowRootLayoutTree(WhitespaceAttacher&);
-  inline void CheckForEmptyStyleChange();
+  inline void CheckForEmptyStyleChange(const Node* node_before_change,
+                                       const Node* node_after_change);
 
   void UpdatePseudoElement(PseudoId, StyleRecalcChange);
   bool UpdateFirstLetter(Element*);
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 539d078b..27af716 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -91,6 +91,7 @@
 #include "core/html/custom/CustomElement.h"
 #include "core/html_names.h"
 #include "core/input/EventHandler.h"
+#include "core/input/InputDeviceCapabilities.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/mathml_names.h"
@@ -2351,16 +2352,47 @@
   DispatchEvent(PointerEvent::Create(pointer_event_name, pointer_event_init));
 }
 
-void Node::DispatchMouseEvent(const WebMouseEvent& native_event,
+// TODO(crbug.com/665924): This function bypasses all Blink event path.
+// It should be using that flow instead of creating/sending events directly.
+void Node::DispatchMouseEvent(const WebMouseEvent& event,
                               const AtomicString& mouse_event_type,
                               int detail,
                               const String& canvas_region_id,
                               Node* related_target) {
-  CreateAndDispatchPointerEvent(mouse_event_type, native_event,
+  CreateAndDispatchPointerEvent(mouse_event_type, event,
                                 GetDocument().domWindow());
-  DispatchEvent(MouseEvent::Create(mouse_event_type, GetDocument().domWindow(),
-                                   native_event, detail, canvas_region_id,
-                                   related_target));
+
+  bool is_mouse_enter_or_leave =
+      mouse_event_type == EventTypeNames::mouseenter ||
+      mouse_event_type == EventTypeNames::mouseleave;
+  MouseEventInit initializer;
+  initializer.setBubbles(!is_mouse_enter_or_leave);
+  initializer.setCancelable(!is_mouse_enter_or_leave);
+  MouseEvent::SetCoordinatesFromWebPointerProperties(
+      event.FlattenTransform(), GetDocument().domWindow(), initializer);
+  initializer.setButton(static_cast<short>(event.button));
+  initializer.setButtons(
+      MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()));
+  initializer.setView(GetDocument().domWindow());
+  initializer.setDetail(detail);
+  initializer.setComposed(true);
+  initializer.setRegion(canvas_region_id);
+  initializer.setRelatedTarget(related_target);
+  UIEventWithKeyState::SetFromWebInputEventModifiers(
+      initializer, static_cast<WebInputEvent::Modifiers>(event.GetModifiers()));
+  initializer.setSourceCapabilities(
+      GetDocument().domWindow() ? GetDocument()
+                                      .domWindow()
+                                      ->GetInputDeviceCapabilities()
+                                      ->FiresTouchEvents(event.FromTouch())
+                                : nullptr);
+
+  DispatchEvent(MouseEvent::Create(
+      mouse_event_type, initializer,
+      TimeTicksFromSeconds(event.TimeStampSeconds()),
+      event.FromTouch() ? MouseEvent::kFromTouch
+                        : MouseEvent::kRealOrIndistinguishable,
+      event.menu_source_type));
 }
 
 void Node::DispatchSimulatedClick(Event* underlying_event,
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index 0a3005a..87451bd 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -129,6 +129,7 @@
     "commands/FormatBlockCommand.h",
     "commands/IndentOutdentCommand.cpp",
     "commands/IndentOutdentCommand.h",
+    "commands/InsertCommands.cpp",
     "commands/InsertCommands.h",
     "commands/InsertIncrementalTextCommand.cpp",
     "commands/InsertIncrementalTextCommand.h",
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index d576b74..99f7566a 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -34,7 +34,6 @@
 #include "core/css/CSSValueList.h"
 #include "core/css_property_names.h"
 #include "core/css_value_keywords.h"
-#include "core/dom/DocumentFragment.h"
 #include "core/dom/TagCollection.h"
 #include "core/dom/events/Event.h"
 #include "core/editing/EditingStyleUtilities.h"
@@ -55,19 +54,14 @@
 #include "core/editing/commands/FormatBlockCommand.h"
 #include "core/editing/commands/IndentOutdentCommand.h"
 #include "core/editing/commands/InsertCommands.h"
-#include "core/editing/commands/InsertListCommand.h"
 #include "core/editing/commands/RemoveFormatCommand.h"
-#include "core/editing/commands/ReplaceSelectionCommand.h"
 #include "core/editing/commands/TypingCommand.h"
 #include "core/editing/commands/UnlinkCommand.h"
 #include "core/editing/iterators/TextIterator.h"
-#include "core/editing/serializers/Serialization.h"
 #include "core/editing/spellcheck/SpellChecker.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/html/HTMLFontElement.h"
-#include "core/html/HTMLHRElement.h"
-#include "core/html/HTMLImageElement.h"
 #include "core/html_names.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutBox.h"
@@ -259,18 +253,6 @@
 static const bool kNotTextInsertion = false;
 static const bool kIsTextInsertion = true;
 
-// Related to Editor::selectionForCommand.
-// Certain operations continue to use the target control's selection even if the
-// event handler already moved the selection outside of the text control.
-LocalFrame* InsertCommands::TargetFrame(LocalFrame& frame, Event* event) {
-  if (!event)
-    return &frame;
-  Node* node = event->target()->ToNode();
-  if (!node)
-    return &frame;
-  return node->GetDocument().GetFrame();
-}
-
 static void ApplyStyle(LocalFrame& frame,
                        CSSPropertyValueSet* style,
                        InputEvent::InputType input_type) {
@@ -445,27 +427,6 @@
   return false;
 }
 
-bool InsertCommands::ExecuteInsertFragment(LocalFrame& frame,
-                                           DocumentFragment* fragment) {
-  DCHECK(frame.GetDocument());
-  return ReplaceSelectionCommand::Create(
-             *frame.GetDocument(), fragment,
-             ReplaceSelectionCommand::kPreventNesting,
-             InputEvent::InputType::kNone)
-      ->Apply();
-}
-
-bool InsertCommands::ExecuteInsertElement(LocalFrame& frame,
-                                          HTMLElement* content) {
-  DCHECK(frame.GetDocument());
-  DocumentFragment* fragment = DocumentFragment::Create(*frame.GetDocument());
-  DummyExceptionStateForTesting exception_state;
-  fragment->AppendChild(content, exception_state);
-  if (exception_state.HadException())
-    return false;
-  return ExecuteInsertFragment(frame, fragment);
-}
-
 bool ExpandSelectionToGranularity(LocalFrame& frame,
                                   TextGranularity granularity) {
   const VisibleSelection& selection = CreateVisibleSelectionWithGranularity(
@@ -1089,133 +1050,6 @@
       ->Apply();
 }
 
-bool InsertCommands::ExecuteInsertBacktab(LocalFrame& frame,
-                                          Event* event,
-                                          EditorCommandSource,
-                                          const String&) {
-  return TargetFrame(frame, event)
-      ->GetEventHandler()
-      .HandleTextInputEvent("\t", event);
-}
-
-bool InsertCommands::ExecuteInsertHorizontalRule(LocalFrame& frame,
-                                                 Event*,
-                                                 EditorCommandSource,
-                                                 const String& value) {
-  DCHECK(frame.GetDocument());
-  HTMLHRElement* rule = HTMLHRElement::Create(*frame.GetDocument());
-  if (!value.IsEmpty())
-    rule->SetIdAttribute(AtomicString(value));
-  return ExecuteInsertElement(frame, rule);
-}
-
-bool InsertCommands::ExecuteInsertHTML(LocalFrame& frame,
-                                       Event*,
-                                       EditorCommandSource,
-                                       const String& value) {
-  DCHECK(frame.GetDocument());
-  return ExecuteInsertFragment(
-      frame, CreateFragmentFromMarkup(*frame.GetDocument(), value, ""));
-}
-
-bool InsertCommands::ExecuteInsertImage(LocalFrame& frame,
-                                        Event*,
-                                        EditorCommandSource,
-                                        const String& value) {
-  DCHECK(frame.GetDocument());
-  HTMLImageElement* image = HTMLImageElement::Create(*frame.GetDocument());
-  if (!value.IsEmpty())
-    image->SetSrc(value);
-  return ExecuteInsertElement(frame, image);
-}
-
-bool InsertCommands::ExecuteInsertLineBreak(LocalFrame& frame,
-                                            Event* event,
-                                            EditorCommandSource source,
-                                            const String&) {
-  switch (source) {
-    case EditorCommandSource::kMenuOrKeyBinding:
-      return TargetFrame(frame, event)
-          ->GetEventHandler()
-          .HandleTextInputEvent("\n", event, kTextEventInputLineBreak);
-    case EditorCommandSource::kDOM:
-      // Doesn't scroll to make the selection visible, or modify the kill ring.
-      // InsertLineBreak is not implemented in IE or Firefox, so this behavior
-      // is only needed for backward compatibility with ourselves, and for
-      // consistency with other commands.
-      DCHECK(frame.GetDocument());
-      return TypingCommand::InsertLineBreak(*frame.GetDocument());
-  }
-  NOTREACHED();
-  return false;
-}
-
-bool InsertCommands::ExecuteInsertNewline(LocalFrame& frame,
-                                          Event* event,
-                                          EditorCommandSource,
-                                          const String&) {
-  LocalFrame* target_frame = TargetFrame(frame, event);
-  return target_frame->GetEventHandler().HandleTextInputEvent(
-      "\n", event,
-      target_frame->GetEditor().CanEditRichly() ? kTextEventInputKeyboard
-                                                : kTextEventInputLineBreak);
-}
-
-bool InsertCommands::ExecuteInsertNewlineInQuotedContent(LocalFrame& frame,
-                                                         Event*,
-                                                         EditorCommandSource,
-                                                         const String&) {
-  DCHECK(frame.GetDocument());
-  return TypingCommand::InsertParagraphSeparatorInQuotedContent(
-      *frame.GetDocument());
-}
-
-bool InsertCommands::ExecuteInsertOrderedList(LocalFrame& frame,
-                                              Event*,
-                                              EditorCommandSource,
-                                              const String&) {
-  DCHECK(frame.GetDocument());
-  return InsertListCommand::Create(*frame.GetDocument(),
-                                   InsertListCommand::kOrderedList)
-      ->Apply();
-}
-
-bool InsertCommands::ExecuteInsertParagraph(LocalFrame& frame,
-                                            Event*,
-                                            EditorCommandSource,
-                                            const String&) {
-  DCHECK(frame.GetDocument());
-  return TypingCommand::InsertParagraphSeparator(*frame.GetDocument());
-}
-
-bool InsertCommands::ExecuteInsertTab(LocalFrame& frame,
-                                      Event* event,
-                                      EditorCommandSource,
-                                      const String&) {
-  return TargetFrame(frame, event)
-      ->GetEventHandler()
-      .HandleTextInputEvent("\t", event);
-}
-
-bool InsertCommands::ExecuteInsertText(LocalFrame& frame,
-                                       Event*,
-                                       EditorCommandSource,
-                                       const String& value) {
-  DCHECK(frame.GetDocument());
-  TypingCommand::InsertText(*frame.GetDocument(), value, 0);
-  return true;
-}
-
-bool InsertCommands::ExecuteInsertUnorderedList(LocalFrame& frame,
-                                                Event*,
-                                                EditorCommandSource,
-                                                const String&) {
-  DCHECK(frame.GetDocument());
-  return InsertListCommand::Create(*frame.GetDocument(),
-                                   InsertListCommand::kUnorderedList)
-      ->Apply();
-}
-
 static bool ExecuteJustifyCenter(LocalFrame& frame,
                                  Event*,
                                  EditorCommandSource source,
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertCommands.cpp b/third_party/WebKit/Source/core/editing/commands/InsertCommands.cpp
new file mode 100644
index 0000000..c48d7ebe
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/commands/InsertCommands.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/commands/InsertCommands.h"
+
+#include "core/dom/DocumentFragment.h"
+#include "core/editing/Editor.h"
+#include "core/editing/commands/InsertListCommand.h"
+#include "core/editing/commands/ReplaceSelectionCommand.h"
+#include "core/editing/commands/TypingCommand.h"
+#include "core/editing/serializers/Serialization.h"
+#include "core/frame/LocalFrame.h"
+#include "core/html/HTMLHRElement.h"
+#include "core/html/HTMLImageElement.h"
+#include "core/input/EventHandler.h"
+
+namespace blink {
+
+LocalFrame& InsertCommands::TargetFrame(LocalFrame& frame, Event* event) {
+  if (!event)
+    return frame;
+  const Node* node = event->target()->ToNode();
+  if (!node)
+    return frame;
+  LocalFrame* local_frame = node->GetDocument().GetFrame();
+  DCHECK(local_frame);
+  return *local_frame;
+}
+
+bool InsertCommands::ExecuteInsertFragment(LocalFrame& frame,
+                                           DocumentFragment* fragment) {
+  DCHECK(frame.GetDocument());
+  return ReplaceSelectionCommand::Create(
+             *frame.GetDocument(), fragment,
+             ReplaceSelectionCommand::kPreventNesting,
+             InputEvent::InputType::kNone)
+      ->Apply();
+}
+
+bool InsertCommands::ExecuteInsertElement(LocalFrame& frame,
+                                          HTMLElement* content) {
+  DCHECK(frame.GetDocument());
+  DocumentFragment* const fragment =
+      DocumentFragment::Create(*frame.GetDocument());
+  DummyExceptionStateForTesting exception_state;
+  fragment->AppendChild(content, exception_state);
+  if (exception_state.HadException())
+    return false;
+  return ExecuteInsertFragment(frame, fragment);
+}
+
+bool InsertCommands::ExecuteInsertBacktab(LocalFrame& frame,
+                                          Event* event,
+                                          EditorCommandSource,
+                                          const String&) {
+  return TargetFrame(frame, event)
+      .GetEventHandler()
+      .HandleTextInputEvent("\t", event);
+}
+
+bool InsertCommands::ExecuteInsertHorizontalRule(LocalFrame& frame,
+                                                 Event*,
+                                                 EditorCommandSource,
+                                                 const String& value) {
+  DCHECK(frame.GetDocument());
+  HTMLHRElement* const rule = HTMLHRElement::Create(*frame.GetDocument());
+  if (!value.IsEmpty())
+    rule->SetIdAttribute(AtomicString(value));
+  return ExecuteInsertElement(frame, rule);
+}
+
+bool InsertCommands::ExecuteInsertHTML(LocalFrame& frame,
+                                       Event*,
+                                       EditorCommandSource,
+                                       const String& value) {
+  DCHECK(frame.GetDocument());
+  return ExecuteInsertFragment(
+      frame, CreateFragmentFromMarkup(*frame.GetDocument(), value, ""));
+}
+
+bool InsertCommands::ExecuteInsertImage(LocalFrame& frame,
+                                        Event*,
+                                        EditorCommandSource,
+                                        const String& value) {
+  DCHECK(frame.GetDocument());
+  HTMLImageElement* const image =
+      HTMLImageElement::Create(*frame.GetDocument());
+  if (!value.IsEmpty())
+    image->SetSrc(value);
+  return ExecuteInsertElement(frame, image);
+}
+
+bool InsertCommands::ExecuteInsertLineBreak(LocalFrame& frame,
+                                            Event* event,
+                                            EditorCommandSource source,
+                                            const String&) {
+  switch (source) {
+    case EditorCommandSource::kMenuOrKeyBinding:
+      return TargetFrame(frame, event)
+          .GetEventHandler()
+          .HandleTextInputEvent("\n", event, kTextEventInputLineBreak);
+    case EditorCommandSource::kDOM:
+      // Doesn't scroll to make the selection visible, or modify the kill ring.
+      // InsertLineBreak is not implemented in IE or Firefox, so this behavior
+      // is only needed for backward compatibility with ourselves, and for
+      // consistency with other commands.
+      DCHECK(frame.GetDocument());
+      return TypingCommand::InsertLineBreak(*frame.GetDocument());
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool InsertCommands::ExecuteInsertNewline(LocalFrame& frame,
+                                          Event* event,
+                                          EditorCommandSource,
+                                          const String&) {
+  const LocalFrame& target_frame = TargetFrame(frame, event);
+  return target_frame.GetEventHandler().HandleTextInputEvent(
+      "\n", event,
+      target_frame.GetEditor().CanEditRichly() ? kTextEventInputKeyboard
+                                               : kTextEventInputLineBreak);
+}
+
+bool InsertCommands::ExecuteInsertNewlineInQuotedContent(LocalFrame& frame,
+                                                         Event*,
+                                                         EditorCommandSource,
+                                                         const String&) {
+  DCHECK(frame.GetDocument());
+  return TypingCommand::InsertParagraphSeparatorInQuotedContent(
+      *frame.GetDocument());
+}
+
+bool InsertCommands::ExecuteInsertOrderedList(LocalFrame& frame,
+                                              Event*,
+                                              EditorCommandSource,
+                                              const String&) {
+  DCHECK(frame.GetDocument());
+  return InsertListCommand::Create(*frame.GetDocument(),
+                                   InsertListCommand::kOrderedList)
+      ->Apply();
+}
+
+bool InsertCommands::ExecuteInsertParagraph(LocalFrame& frame,
+                                            Event*,
+                                            EditorCommandSource,
+                                            const String&) {
+  DCHECK(frame.GetDocument());
+  return TypingCommand::InsertParagraphSeparator(*frame.GetDocument());
+}
+
+bool InsertCommands::ExecuteInsertTab(LocalFrame& frame,
+                                      Event* event,
+                                      EditorCommandSource,
+                                      const String&) {
+  return TargetFrame(frame, event)
+      .GetEventHandler()
+      .HandleTextInputEvent("\t", event);
+}
+
+bool InsertCommands::ExecuteInsertText(LocalFrame& frame,
+                                       Event*,
+                                       EditorCommandSource,
+                                       const String& value) {
+  DCHECK(frame.GetDocument());
+  TypingCommand::InsertText(*frame.GetDocument(), value, 0);
+  return true;
+}
+
+bool InsertCommands::ExecuteInsertUnorderedList(LocalFrame& frame,
+                                                Event*,
+                                                EditorCommandSource,
+                                                const String&) {
+  DCHECK(frame.GetDocument());
+  return InsertListCommand::Create(*frame.GetDocument(),
+                                   InsertListCommand::kUnorderedList)
+      ->Apply();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertCommands.h b/third_party/WebKit/Source/core/editing/commands/InsertCommands.h
index e5047b7c..2f1df353 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertCommands.h
+++ b/third_party/WebKit/Source/core/editing/commands/InsertCommands.h
@@ -106,7 +106,7 @@
   // Related to Editor::selectionForCommand.
   // Certain operations continue to use the target control's selection even if
   // the event handler already moved the selection outside of the text control.
-  static LocalFrame* TargetFrame(LocalFrame&, Event*);
+  static LocalFrame& TargetFrame(LocalFrame&, Event*);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/events/DragEvent.cpp b/third_party/WebKit/Source/core/events/DragEvent.cpp
index 7ea98f7c..eb1e8d1 100644
--- a/third_party/WebKit/Source/core/events/DragEvent.cpp
+++ b/third_party/WebKit/Source/core/events/DragEvent.cpp
@@ -10,80 +10,13 @@
 
 namespace blink {
 
-DragEvent* DragEvent::Create(const AtomicString& type,
-                             Bubbles bubbles,
-                             Cancelable cancelable,
-                             AbstractView* view,
-                             int detail,
-                             double screen_x,
-                             double screen_y,
-                             double window_x,
-                             double window_y,
-                             double movement_x,
-                             double movement_y,
-                             WebInputEvent::Modifiers modifiers,
-                             short button,
-                             unsigned short buttons,
-                             EventTarget* related_target,
-                             TimeTicks platform_time_stamp,
-                             DataTransfer* data_transfer,
-                             SyntheticEventType synthetic_event_type) {
-  return new DragEvent(
-      type, bubbles, cancelable, view, detail, screen_x, screen_y, window_x,
-      window_y, movement_x, movement_y, modifiers, button, buttons,
-      related_target, platform_time_stamp, data_transfer, synthetic_event_type);
-}
-
 DragEvent::DragEvent() : data_transfer_(nullptr) {}
 
-DragEvent::DragEvent(DataTransfer* data_transfer)
-    : data_transfer_(data_transfer) {}
-
-DragEvent::DragEvent(const AtomicString& event_type,
-                     Bubbles bubbles,
-                     Cancelable cancelable,
-                     AbstractView* view,
-                     int detail,
-                     double screen_x,
-                     double screen_y,
-                     double window_x,
-                     double window_y,
-                     double movement_x,
-                     double movement_y,
-                     WebInputEvent::Modifiers modifiers,
-                     short button,
-                     unsigned short buttons,
-                     EventTarget* related_target,
+DragEvent::DragEvent(const AtomicString& type,
+                     const DragEventInit& initializer,
                      TimeTicks platform_time_stamp,
-                     DataTransfer* data_transfer,
                      SyntheticEventType synthetic_event_type)
-    : MouseEvent(
-          event_type,
-          bubbles,
-          cancelable,
-          view,
-          detail,
-          screen_x,
-          screen_y,
-          window_x,
-          window_y,
-          movement_x,
-          movement_y,
-          modifiers,
-          button,
-          buttons,
-          related_target,
-          platform_time_stamp,
-          synthetic_event_type,
-          // TODO(zino): Should support canvas hit region because the drag event
-          // is a kind of mouse event. Please see http://crbug.com/594073
-          String()),
-      data_transfer_(data_transfer)
-
-{}
-
-DragEvent::DragEvent(const AtomicString& type, const DragEventInit& initializer)
-    : MouseEvent(type, initializer),
+    : MouseEvent(type, initializer, platform_time_stamp, synthetic_event_type),
       data_transfer_(initializer.getDataTransfer()) {}
 
 bool DragEvent::IsDragEvent() const {
diff --git a/third_party/WebKit/Source/core/events/DragEvent.h b/third_party/WebKit/Source/core/events/DragEvent.h
index 75cd6f4d5..b2cdbbe 100644
--- a/third_party/WebKit/Source/core/events/DragEvent.h
+++ b/third_party/WebKit/Source/core/events/DragEvent.h
@@ -19,32 +19,18 @@
  public:
   static DragEvent* Create() { return new DragEvent; }
 
-  static DragEvent* Create(DataTransfer* data_transfer) {
-    return new DragEvent(data_transfer);
+  static DragEvent* Create(const AtomicString& type,
+                           const DragEventInit& initializer,
+                           TimeTicks platform_time_stamp,
+                           SyntheticEventType synthetic_event_type) {
+    return new DragEvent(type, initializer, platform_time_stamp,
+                         synthetic_event_type);
   }
 
   static DragEvent* Create(const AtomicString& type,
-                           Bubbles,
-                           Cancelable,
-                           AbstractView*,
-                           int detail,
-                           double screen_x,
-                           double screen_y,
-                           double window_x,
-                           double window_y,
-                           double movement_x,
-                           double movement_y,
-                           WebInputEvent::Modifiers,
-                           short button,
-                           unsigned short buttons,
-                           EventTarget* related_target,
-                           TimeTicks platform_time_stamp,
-                           DataTransfer*,
-                           SyntheticEventType = kRealOrIndistinguishable);
-
-  static DragEvent* Create(const AtomicString& type,
                            const DragEventInit& initializer) {
-    return new DragEvent(type, initializer);
+    return new DragEvent(type, initializer, CurrentTimeTicks(),
+                         kRealOrIndistinguishable);
   }
 
   DataTransfer* getDataTransfer() const override {
@@ -60,28 +46,11 @@
 
  private:
   DragEvent();
-  DragEvent(DataTransfer*);
   DragEvent(const AtomicString& type,
-            Bubbles,
-            Cancelable,
-            AbstractView*,
-            int detail,
-            double screen_x,
-            double screen_y,
-            double window_x,
-            double window_y,
-            double movement_x,
-            double movement_y,
-            WebInputEvent::Modifiers,
-            short button,
-            unsigned short buttons,
-            EventTarget* related_target,
+            const DragEventInit&,
             TimeTicks platform_time_stamp,
-            DataTransfer*,
             SyntheticEventType);
 
-  DragEvent(const AtomicString& type, const DragEventInit&);
-
   Member<DataTransfer> data_transfer_;
 };
 
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp
index 3107290..b0727d9 100644
--- a/third_party/WebKit/Source/core/events/MouseEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -94,18 +94,12 @@
 }
 
 MouseEvent* MouseEvent::Create(const AtomicString& event_type,
-                               AbstractView* view,
-                               const WebMouseEvent& event,
-                               int detail,
-                               const String& canvas_region_id,
-                               Node* related_target) {
-  bool is_mouse_enter_or_leave = event_type == EventTypeNames::mouseenter ||
-                                 event_type == EventTypeNames::mouseleave;
-  Cancelable cancelable =
-      (!is_mouse_enter_or_leave) ? Cancelable::kYes : Cancelable::kNo;
-  Bubbles bubbles = (!is_mouse_enter_or_leave) ? Bubbles::kYes : Bubbles::kNo;
-  return new MouseEvent(event_type, bubbles, cancelable, view, event, detail,
-                        canvas_region_id, related_target);
+                               const MouseEventInit& initializer,
+                               TimeTicks platform_time_stamp,
+                               SyntheticEventType synthetic_event_type,
+                               WebMenuSourceType menu_source_type) {
+  return new MouseEvent(event_type, initializer, platform_time_stamp,
+                        synthetic_event_type, menu_source_type);
 }
 
 MouseEvent* MouseEvent::Create(const AtomicString& event_type,
@@ -128,12 +122,19 @@
     screen_y = mouse_event->screenY();
   }
 
+  MouseEventInit initializer;
+  initializer.setBubbles(true);
+  initializer.setCancelable(true);
+  initializer.setScreenX(screen_x);
+  initializer.setScreenY(screen_y);
+  initializer.setView(view);
+  initializer.setComposed(true);
+  UIEventWithKeyState::SetFromWebInputEventModifiers(initializer, modifiers);
+
   TimeTicks timestamp = underlying_event ? underlying_event->PlatformTimeStamp()
                                          : CurrentTimeTicks();
   MouseEvent* created_event =
-      new MouseEvent(event_type, Bubbles::kYes, Cancelable::kYes, view, 0,
-                     screen_x, screen_y, 0, 0, 0, 0, modifiers, 0, 0, nullptr,
-                     timestamp, synthetic_type, String());
+      new MouseEvent(event_type, initializer, timestamp, synthetic_type);
 
   created_event->SetTrusted(creation_scope ==
                             SimulatedClickCreationScope::kFromUserAgent);
@@ -156,97 +157,24 @@
       synthetic_event_type_(kRealOrIndistinguishable) {}
 
 MouseEvent::MouseEvent(const AtomicString& event_type,
-                       Bubbles bubbles,
-                       Cancelable cancelable,
-                       AbstractView* abstract_view,
-                       const WebMouseEvent& event,
-                       int detail,
-                       const String& region,
-                       EventTarget* related_target)
-    : UIEventWithKeyState(
-          event_type,
-          bubbles,
-          cancelable,
-          abstract_view,
-          detail,
-          static_cast<WebInputEvent::Modifiers>(event.GetModifiers()),
-          TimeTicksFromSeconds(event.TimeStampSeconds()),
-          abstract_view
-              ? abstract_view->GetInputDeviceCapabilities()->FiresTouchEvents(
-                    event.FromTouch())
-              : nullptr),
-      screen_location_(event.PositionInScreen().x, event.PositionInScreen().y),
-      movement_delta_(event.MovementInRootFrame()),
-      position_type_(PositionType::kPosition),
-      button_(static_cast<short>(event.button)),
-      buttons_(WebInputEventModifiersToButtons(event.GetModifiers())),
-      related_target_(related_target),
-      synthetic_event_type_(event.FromTouch() ? kFromTouch
-                                              : kRealOrIndistinguishable),
-      region_(region),
-      menu_source_type_(event.menu_source_type) {
-  FloatPoint root_frame_coordinates = event.PositionInRootFrame();
-  InitCoordinatesFromRootFrame(root_frame_coordinates.X(),
-                               root_frame_coordinates.Y());
-}
-
-MouseEvent::MouseEvent(const AtomicString& event_type,
-                       Bubbles bubbles,
-                       Cancelable cancelable,
-                       AbstractView* abstract_view,
-                       int detail,
-                       double screen_x,
-                       double screen_y,
-                       double window_x,
-                       double window_y,
-                       double movement_x,
-                       double movement_y,
-                       WebInputEvent::Modifiers modifiers,
-                       short button,
-                       unsigned short buttons,
-                       EventTarget* related_target,
+                       const MouseEventInit& initializer,
                        TimeTicks platform_time_stamp,
                        SyntheticEventType synthetic_event_type,
-                       const String& region)
-    : UIEventWithKeyState(
-          event_type,
-          bubbles,
-          cancelable,
-          abstract_view,
-          detail,
-          modifiers,
-          platform_time_stamp,
-          abstract_view
-              ? abstract_view->GetInputDeviceCapabilities()->FiresTouchEvents(
-                    synthetic_event_type == kFromTouch)
-              : nullptr),
-      screen_location_(screen_x, screen_y),
-      movement_delta_(movement_x, movement_y),
-      position_type_(synthetic_event_type == kPositionless
-                         ? PositionType::kPositionless
-                         : PositionType::kPosition),
-      button_(button),
-      buttons_(buttons),
-      related_target_(related_target),
-      synthetic_event_type_(synthetic_event_type),
-      region_(region) {
-  InitCoordinatesFromRootFrame(window_x, window_y);
-}
-
-MouseEvent::MouseEvent(const AtomicString& event_type,
-                       const MouseEventInit& initializer,
-                       TimeTicks platform_time_stamp)
+                       WebMenuSourceType menu_source_type)
     : UIEventWithKeyState(event_type, initializer, platform_time_stamp),
       screen_location_(
           DoublePoint(initializer.screenX(), initializer.screenY())),
       movement_delta_(
           IntPoint(initializer.movementX(), initializer.movementY())),
-      position_type_(PositionType::kPosition),
+      position_type_(synthetic_event_type == kPositionless
+                         ? PositionType::kPositionless
+                         : PositionType::kPosition),
       button_(initializer.button()),
       buttons_(initializer.buttons()),
       related_target_(initializer.relatedTarget()),
-      synthetic_event_type_(kRealOrIndistinguishable),
-      region_(initializer.region()) {
+      synthetic_event_type_(synthetic_event_type),
+      region_(initializer.region()),
+      menu_source_type_(menu_source_type) {
   InitCoordinates(initializer.clientX(), initializer.clientY());
 }
 
@@ -263,35 +191,32 @@
   has_cached_relative_position_ = false;
 }
 
-void MouseEvent::InitCoordinatesFromRootFrame(double window_x,
-                                              double window_y) {
-  DoublePoint adjusted_page_location;
-  DoubleSize scroll_offset;
-
-  LocalFrame* frame = view() && view()->IsLocalDOMWindow()
-                          ? ToLocalDOMWindow(view())->GetFrame()
-                          : nullptr;
-  if (frame && HasPosition()) {
-    scroll_offset = ContentsScrollOffset(view());
-    if (LocalFrameView* frame_view = frame->View()) {
-      adjusted_page_location =
-          frame_view->RootFrameToDocument(FloatPoint(window_x, window_y));
-      float scale_factor = 1 / frame->PageZoomFactor();
-      if (scale_factor != 1.0f)
-        adjusted_page_location.Scale(scale_factor, scale_factor);
-    }
+void MouseEvent::SetCoordinatesFromWebPointerProperties(
+    const WebPointerProperties& web_pointer_properties,
+    const LocalDOMWindow* dom_window,
+    MouseEventInit& initializer) {
+  FloatPoint client_point;
+  float scale_factor = 1.0f;
+  if (dom_window && dom_window->GetFrame() && dom_window->GetFrame()->View()) {
+    LocalFrame* frame = dom_window->GetFrame();
+    FloatPoint page_point = frame->View()->RootFrameToContents(
+        web_pointer_properties.PositionInWidget());
+    scale_factor = 1.0f / frame->PageZoomFactor();
+    FloatPoint scroll_position(frame->View()->GetScrollOffset());
+    client_point = page_point.ScaledBy(scale_factor);
+    client_point.MoveBy(scroll_position.ScaledBy(-scale_factor));
   }
 
-  client_location_ = adjusted_page_location - scroll_offset;
-  page_location_ = adjusted_page_location;
+  initializer.setScreenX(web_pointer_properties.PositionInScreen().x);
+  initializer.setScreenY(web_pointer_properties.PositionInScreen().y);
+  initializer.setClientX(client_point.X());
+  initializer.setClientY(client_point.Y());
 
-  // Set up initial values for coordinates.
-  // Correct values are computed lazily, see computeRelativePosition.
-  layer_location_ = page_location_;
-  offset_location_ = page_location_;
-
-  ComputePageLocation();
-  has_cached_relative_position_ = false;
+  // TODO(nzolghadr): We need to scale movement attrinutes as well. But if we do
+  // that here and round it to the int again it causes inconsistencies between
+  // screenX/Y and cumulative movementX/Y.
+  initializer.setMovementX(web_pointer_properties.movement_x);
+  initializer.setMovementY(web_pointer_properties.movement_y);
 }
 
 MouseEvent::~MouseEvent() = default;
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.h b/third_party/WebKit/Source/core/events/MouseEvent.h
index 7530275..0b5efa7 100644
--- a/third_party/WebKit/Source/core/events/MouseEvent.h
+++ b/third_party/WebKit/Source/core/events/MouseEvent.h
@@ -28,7 +28,6 @@
 #include "core/events/MouseEventInit.h"
 #include "core/events/UIEventWithKeyState.h"
 #include "public/platform/WebMenuSourceType.h"
-#include "public/platform/WebMouseEvent.h"
 
 namespace blink {
 class DataTransfer;
@@ -52,11 +51,10 @@
   static MouseEvent* Create() { return new MouseEvent; }
 
   static MouseEvent* Create(const AtomicString& event_type,
-                            AbstractView*,
-                            const WebMouseEvent&,
-                            int detail,
-                            const String& canvas_region_id,
-                            Node* related_target);
+                            const MouseEventInit&,
+                            TimeTicks platform_time_stamp,
+                            SyntheticEventType,
+                            WebMenuSourceType);
 
   static MouseEvent* Create(ScriptState*,
                             const AtomicString& event_type,
@@ -70,6 +68,10 @@
   ~MouseEvent() override;
 
   static unsigned short WebInputEventModifiersToButtons(unsigned modifiers);
+  static void SetCoordinatesFromWebPointerProperties(
+      const WebPointerProperties&,
+      const LocalDOMWindow*,
+      MouseEventInit&);
 
   void initMouseEvent(ScriptState*,
                       const AtomicString& type,
@@ -117,8 +119,6 @@
 
   int ClickCount() { return detail(); }
 
-  const WebMouseEvent* NativeEvent() const { return native_event_.get(); }
-
   enum class PositionType {
     kPosition,
     // Positionless mouse events are used, for example, for 'click' events from
@@ -192,36 +192,11 @@
 
  protected:
   MouseEvent(const AtomicString& type,
-             Bubbles,
-             Cancelable,
-             AbstractView*,
-             const WebMouseEvent&,
-             int detail,
-             const String& region,
-             EventTarget* related_target);
-
-  MouseEvent(const AtomicString& type,
-             Bubbles,
-             Cancelable,
-             AbstractView*,
-             int detail,
-             double screen_x,
-             double screen_y,
-             double window_x,
-             double window_y,
-             double movement_x,
-             double movement_y,
-             WebInputEvent::Modifiers,
-             short button,
-             unsigned short buttons,
-             EventTarget* related_target,
-             TimeTicks platform_time_stamp,
-             SyntheticEventType,
-             const String& region);
-
-  MouseEvent(const AtomicString& type,
              const MouseEventInit&,
-             TimeTicks platform_time_stamp);
+             TimeTicks platform_time_stamp,
+             SyntheticEventType = kRealOrIndistinguishable,
+             WebMenuSourceType = kMenuSourceNone);
+
   MouseEvent(const AtomicString& type, const MouseEventInit& init)
       : MouseEvent(type, init, CurrentTimeTicks()) {}
 
@@ -254,7 +229,6 @@
                               unsigned short buttons = 0);
 
   void InitCoordinates(const double client_x, const double client_y);
-  void InitCoordinatesFromRootFrame(double window_x, double window_y);
 
   void ComputePageLocation();
   void ComputeRelativePosition();
@@ -274,8 +248,6 @@
 
   // Only used for contextmenu events.
   WebMenuSourceType menu_source_type_;
-
-  std::unique_ptr<WebMouseEvent> native_event_;
 };
 
 DEFINE_EVENT_TYPE_CASTS(MouseEvent);
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 8258bb3..55b2f9dc 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -88,31 +88,16 @@
   WebPointerEvent web_pointer_event_in_root_frame =
       web_pointer_event.WebPointerEventInRootFrame();
 
-  FloatPoint client_point;
-  float scale_factor = 1.0f;
-  if (dom_window && dom_window->GetFrame() && dom_window->GetFrame()->View()) {
-    LocalFrame* frame = dom_window->GetFrame();
-    FloatPoint page_point = frame->View()->RootFrameToContents(
-        web_pointer_event_in_root_frame.PositionInWidget());
-    scale_factor = 1.0f / frame->PageZoomFactor();
-    FloatPoint scroll_position(frame->View()->GetScrollOffset());
-    client_point = page_point.ScaledBy(scale_factor);
-    client_point.MoveBy(scroll_position.ScaledBy(-scale_factor));
-  }
-
-  pointer_event_init->setScreenX(web_pointer_event.PositionInScreen().x);
-  pointer_event_init->setScreenY(web_pointer_event.PositionInScreen().y);
-  pointer_event_init->setClientX(client_point.X());
-  pointer_event_init->setClientY(client_point.Y());
-  // TODO(nzolghadr): We need to scale movement attrinutes as well. But if we do
-  // that here and round it to the int again it causes inconsistencies between
-  // screenX/Y and cumulative movementX/Y.
-  pointer_event_init->setMovementX(web_pointer_event_in_root_frame.movement_x);
-  pointer_event_init->setMovementY(web_pointer_event_in_root_frame.movement_y);
+  MouseEvent::SetCoordinatesFromWebPointerProperties(
+      web_pointer_event_in_root_frame, dom_window, *pointer_event_init);
   // If width/height is unknown we let PointerEventInit set it to 1.
   // See https://w3c.github.io/pointerevents/#dom-pointerevent-width
   if (web_pointer_event_in_root_frame.HasWidth() &&
       web_pointer_event_in_root_frame.HasHeight()) {
+    float scale_factor = 1.0f;
+    if (dom_window && dom_window->GetFrame())
+      scale_factor = 1.0f / dom_window->GetFrame()->PageZoomFactor();
+
     FloatSize point_shape = FloatSize(web_pointer_event_in_root_frame.width,
                                       web_pointer_event_in_root_frame.height)
                                 .ScaledBy(scale_factor);
diff --git a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
index 52921fc..208e77a4 100644
--- a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
@@ -172,24 +172,6 @@
 WebMouseEventBuilder::WebMouseEventBuilder(const LocalFrameView* plugin_parent,
                                            const LayoutObject* layout_object,
                                            const MouseEvent& event) {
-  if (event.NativeEvent()) {
-    *static_cast<WebMouseEvent*>(this) =
-        event.NativeEvent()->FlattenTransform();
-    WebFloatPoint absolute_location = PositionInRootFrame();
-
-    // TODO(dtapuska): |plugin_parent| should never be null. Remove this
-    // conditional code.
-    // Translate the root frame position to content coordinates.
-    if (plugin_parent) {
-      absolute_location = plugin_parent->RootFrameToContents(absolute_location);
-    }
-
-    FloatPoint local_point =
-        layout_object->AbsoluteToLocal(absolute_location, kUseTransforms);
-    SetPositionInWidget(local_point.X(), local_point.Y());
-    return;
-  }
-
   // Code below here can be removed once OOPIF ships.
   // OOPIF will prevent synthetic events being dispatched into
   // other frames; but for now we allow the fallback to generate
diff --git a/third_party/WebKit/Source/core/events/WheelEvent.cpp b/third_party/WebKit/Source/core/events/WheelEvent.cpp
index 77ec559..33b90bb 100644
--- a/third_party/WebKit/Source/core/events/WheelEvent.cpp
+++ b/third_party/WebKit/Source/core/events/WheelEvent.cpp
@@ -41,6 +41,30 @@
   return -value;
 }
 
+MouseEventInit GetMouseEventInitForWheel(const WebMouseWheelEvent& event,
+                                         AbstractView* view) {
+  MouseEventInit initializer;
+  initializer.setBubbles(true);
+  initializer.setCancelable(event.IsCancelable());
+  MouseEvent::SetCoordinatesFromWebPointerProperties(
+      event.FlattenTransform(),
+      view->IsLocalDOMWindow() ? ToLocalDOMWindow(view) : nullptr, initializer);
+  initializer.setButton(static_cast<short>(event.button));
+  initializer.setButtons(
+      MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()));
+  initializer.setView(view);
+  initializer.setComposed(true);
+  initializer.setDetail(event.click_count);
+  UIEventWithKeyState::SetFromWebInputEventModifiers(
+      initializer, static_cast<WebInputEvent::Modifiers>(event.GetModifiers()));
+
+  // TODO(zino): Should support canvas hit region because the
+  // wheel event is a kind of mouse event. Please see
+  // http://crbug.com/594075
+
+  return initializer;
+}
+
 }  // namespace
 
 WheelEvent* WheelEvent::Create(const WebMouseWheelEvent& event,
@@ -69,16 +93,8 @@
 
 WheelEvent::WheelEvent(const WebMouseWheelEvent& event, AbstractView* view)
     : MouseEvent(EventTypeNames::wheel,
-                 Bubbles::kYes,
-                 event.IsCancelable() ? Cancelable::kYes : Cancelable::kNo,
-                 view,
-                 event,
-                 event.click_count,
-                 // TODO(zino): Should support canvas hit region because the
-                 // wheel event is a kind of mouse event. Please see
-                 // http://crbug.com/594075
-                 String(),
-                 nullptr),
+                 GetMouseEventInitForWheel(event, view),
+                 TimeTicksFromSeconds(event.TimeStampSeconds())),
       wheel_delta_(event.wheel_ticks_x * kTickMultiplier,
                    event.wheel_ticks_y * kTickMultiplier),
       delta_x_(-event.DeltaXInRootFrame()),
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
index a002eac..0289ef1a 100644
--- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -217,10 +217,41 @@
         mouse_event_type == EventTypeNames::dblclick) {
       click_count = click_count_;
     }
+    bool is_mouse_enter_or_leave =
+        mouse_event_type == EventTypeNames::mouseenter ||
+        mouse_event_type == EventTypeNames::mouseleave;
+    MouseEventInit initializer;
+    initializer.setBubbles(!is_mouse_enter_or_leave);
+    initializer.setCancelable(!is_mouse_enter_or_leave);
+    MouseEvent::SetCoordinatesFromWebPointerProperties(
+        mouse_event.FlattenTransform(), target_node->GetDocument().domWindow(),
+        initializer);
+    initializer.setButton(static_cast<short>(mouse_event.button));
+    initializer.setButtons(MouseEvent::WebInputEventModifiersToButtons(
+        mouse_event.GetModifiers()));
+    initializer.setView(target_node->GetDocument().domWindow());
+    initializer.setComposed(true);
+    initializer.setDetail(click_count);
+    initializer.setRegion(canvas_region_id);
+    initializer.setRelatedTarget(related_target);
+    UIEventWithKeyState::SetFromWebInputEventModifiers(
+        initializer,
+        static_cast<WebInputEvent::Modifiers>(mouse_event.GetModifiers()));
+    initializer.setSourceCapabilities(
+        target_node->GetDocument().domWindow()
+            ? target_node->GetDocument()
+                  .domWindow()
+                  ->GetInputDeviceCapabilities()
+                  ->FiresTouchEvents(mouse_event.FromTouch())
+            : nullptr);
+
     MouseEvent* event = MouseEvent::Create(
-        mouse_event_type, target_node->GetDocument().domWindow(), mouse_event,
-        click_count, canvas_region_id,
-        related_target ? related_target->ToNode() : nullptr);
+        mouse_event_type, initializer,
+        TimeTicksFromSeconds(mouse_event.TimeStampSeconds()),
+        mouse_event.FromTouch() ? MouseEvent::kFromTouch
+                                : MouseEvent::kRealOrIndistinguishable,
+        mouse_event.menu_source_type);
+
     DispatchEventResult dispatch_result = target->DispatchEvent(event);
     return EventHandlingUtil::ToWebInputEventResult(dispatch_result);
   }
@@ -1009,22 +1040,32 @@
       related_target->GetDocument() != drag_target->GetDocument())
     related_target = nullptr;
 
-  const Event::Cancelable cancelable =
-      (event_type != EventTypeNames::dragleave &&
-       event_type != EventTypeNames::dragend)
-          ? Event::Cancelable::kYes
-          : Event::Cancelable::kNo;
+  DragEventInit initializer;
+  initializer.setBubbles(true);
+  initializer.setCancelable(event_type != EventTypeNames::dragleave &&
+                            event_type != EventTypeNames::dragend);
+  MouseEvent::SetCoordinatesFromWebPointerProperties(
+      event.FlattenTransform(), frame_->GetDocument()->domWindow(),
+      initializer);
+  initializer.setButton(0);
+  initializer.setButtons(
+      MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()));
+  initializer.setRelatedTarget(related_target);
+  initializer.setView(frame_->GetDocument()->domWindow());
+  initializer.setComposed(true);
+  initializer.setGetDataTransfer(data_transfer);
+  initializer.setSourceCapabilities(
+      frame_->GetDocument()->domWindow()
+          ? frame_->GetDocument()
+                ->domWindow()
+                ->GetInputDeviceCapabilities()
+                ->FiresTouchEvents(event.FromTouch())
+          : nullptr);
+  UIEventWithKeyState::SetFromWebInputEventModifiers(
+      initializer, static_cast<WebInputEvent::Modifiers>(event.GetModifiers()));
 
-  IntPoint movement = FlooredIntPoint(event.MovementInRootFrame());
   DragEvent* me = DragEvent::Create(
-      event_type, Event::Bubbles::kYes, cancelable,
-      frame_->GetDocument()->domWindow(), 0, event.PositionInScreen().x,
-      event.PositionInScreen().y, event.PositionInRootFrame().x,
-      event.PositionInRootFrame().y, movement.X(), movement.Y(),
-      static_cast<WebInputEvent::Modifiers>(event.GetModifiers()), 0,
-      MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()),
-      related_target, TimeTicksFromSeconds(event.TimeStampSeconds()),
-      data_transfer,
+      event_type, initializer, TimeTicksFromSeconds(event.TimeStampSeconds()),
       event.FromTouch() ? MouseEvent::kFromTouch
                         : MouseEvent::kRealOrIndistinguishable);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index 2f37ace..b925e9a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -45,9 +45,11 @@
 #include "core/layout/line/EllipsisBox.h"
 #include "core/layout/line/GlyphOverflow.h"
 #include "core/layout/line/InlineTextBox.h"
+#include "core/layout/ng/geometry/ng_logical_rect.h"
 #include "core/layout/ng/inline/ng_inline_fragment_traversal.h"
 #include "core/layout/ng/inline/ng_inline_node.h"
 #include "core/layout/ng/inline/ng_offset_mapping.h"
+#include "core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "core/layout/ng/layout_ng_block_flow.h"
 #include "platform/fonts/CharacterRange.h"
 #include "platform/geometry/FloatQuad.h"
@@ -263,11 +265,26 @@
 
 Optional<FloatPoint> LayoutText::GetUpperLeftCorner() const {
   DCHECK(!IsBR());
-  // TODO(layoutng) Implement GetUpperLeftCorner for layoutng
-  if (!HasLegacyTextBoxes())
-    return WTF::nullopt;
-  return FloatPoint(LinesBoundingBox().X(),
-                    FirstTextBox()->Root().LineTop().ToFloat());
+  if (HasLegacyTextBoxes()) {
+    if (StyleRef().IsHorizontalWritingMode()) {
+      return FloatPoint(LinesBoundingBox().X(),
+                        FirstTextBox()->Root().LineTop().ToFloat());
+    }
+    return FloatPoint(FirstTextBox()->Root().LineTop().ToFloat(),
+                      LinesBoundingBox().Y());
+  }
+  auto fragments = NGPaintFragment::InlineFragmentsFor(this);
+  if (!fragments.IsEmpty()) {
+    const NGPaintFragment* line_box = fragments.begin()->ContainerLineBox();
+    DCHECK(line_box);
+    if (StyleRef().IsHorizontalWritingMode()) {
+      return FloatPoint(LinesBoundingBox().X(),
+                        line_box->InlineOffsetToContainerBox().top.ToFloat());
+    }
+    return FloatPoint(line_box->InlineOffsetToContainerBox().left.ToFloat(),
+                      LinesBoundingBox().Y());
+  }
+  return WTF::nullopt;
 }
 
 bool LayoutText::HasTextBoxes() const {
@@ -409,6 +426,48 @@
   Quads(quads, kNoClipping, kAbsoluteQuads, mode);
 }
 
+bool LayoutText::MapDOMOffsetToTextContentOffset(const NGOffsetMapping& mapping,
+                                                 unsigned* start,
+                                                 unsigned* end) const {
+  DCHECK_LE(*start, *end);
+
+  // Adjust |start| to the next non-collapsed offset if |start| is collapsed.
+  Position start_position =
+      PositionForCaretOffset(std::min(*start, TextLength()));
+  Position non_collapsed_start_position =
+      mapping.StartOfNextNonCollapsedContent(start_position);
+
+  // If all characters after |start| are collapsed, adjust to the last
+  // non-collapsed offset.
+  if (non_collapsed_start_position.IsNull()) {
+    non_collapsed_start_position =
+        mapping.EndOfLastNonCollapsedContent(start_position);
+
+    // If all characters are collapsed, return false.
+    if (non_collapsed_start_position.IsNull())
+      return false;
+  }
+
+  *start = mapping.GetTextContentOffset(non_collapsed_start_position).value();
+
+  // Adjust |end| to the last non-collapsed offset if |end| is collapsed.
+  Position end_position = PositionForCaretOffset(std::min(*end, TextLength()));
+  Position non_collpased_end_position =
+      mapping.EndOfLastNonCollapsedContent(end_position);
+
+  if (non_collpased_end_position.IsNull() ||
+      non_collpased_end_position.OffsetInContainerNode() <=
+          non_collapsed_start_position.OffsetInContainerNode()) {
+    // If all characters in the range are collapsed, make |end| = |start|.
+    *end = *start;
+  } else {
+    *end = mapping.GetTextContentOffset(non_collpased_end_position).value();
+  }
+
+  DCHECK_LE(*start, *end);
+  return true;
+}
+
 void LayoutText::AbsoluteQuadsForRange(Vector<FloatQuad>& quads,
                                        unsigned start,
                                        unsigned end) const {
@@ -424,6 +483,28 @@
   start = std::min(start, static_cast<unsigned>(INT_MAX));
   end = std::min(end, static_cast<unsigned>(INT_MAX));
 
+  if (auto* mapping = GetNGOffsetMapping()) {
+    if (!MapDOMOffsetToTextContentOffset(*mapping, &start, &end))
+      return;
+
+    // Find fragments that have text for the specified range.
+    DCHECK_LE(start, end);
+    auto fragments = NGPaintFragment::InlineFragmentsFor(this);
+    for (const NGPaintFragment* fragment : fragments) {
+      const NGPhysicalTextFragment& text_fragment =
+          ToNGPhysicalTextFragment(fragment->PhysicalFragment());
+      if (start > text_fragment.EndOffset() ||
+          end < text_fragment.StartOffset())
+        continue;
+      NGPhysicalOffsetRect rect =
+          text_fragment.LocalRect(std::max(start, text_fragment.StartOffset()),
+                                  std::min(end, text_fragment.EndOffset()));
+      rect.offset += fragment->InlineOffsetToContainerBox();
+      quads.push_back(LocalToAbsoluteQuad(rect.ToFloatRect()));
+    }
+    return;
+  }
+
   const unsigned caret_min_offset = static_cast<unsigned>(CaretMinOffset());
   const unsigned caret_max_offset = static_cast<unsigned>(CaretMaxOffset());
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.h b/third_party/WebKit/Source/core/layout/LayoutText.h
index e348d75d..59f0ed6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.h
+++ b/third_party/WebKit/Source/core/layout/LayoutText.h
@@ -198,8 +198,8 @@
   InlineTextBox* FirstTextBox() const { return text_boxes_.First(); }
   InlineTextBox* LastTextBox() const { return text_boxes_.Last(); }
 
-  // Returns upper left corner point in local coordinate if this object has
-  // rendered text.
+  // Returns upper left corner point in local physical coordinates with flipped
+  // block-flow direction if this object has rendered text.
   Optional<FloatPoint> GetUpperLeftCorner() const;
 
   // True if we have inline text box children which implies rendered text (or
@@ -265,6 +265,18 @@
 
   virtual UChar PreviousCharacter() const;
 
+  // Returns the NGOffsetMapping object when the current text is laid out with
+  // LayoutNG.
+  // Note that the text can be in legacy layout even when LayoutNG is enabled,
+  // so we can't simply check the RuntimeEnabledFeature.
+  const NGOffsetMapping* GetNGOffsetMapping() const;
+
+  // Map DOM offset to LayoutNG text content offset.
+  // Returns false if all characters in this LayoutText are collapsed.
+  bool MapDOMOffsetToTextContentOffset(const NGOffsetMapping&,
+                                       unsigned* start,
+                                       unsigned* end) const;
+
  protected:
   void WillBeDestroyed() override;
 
@@ -285,12 +297,6 @@
 
   void InvalidateDisplayItemClients(PaintInvalidationReason) const override;
 
-  // Returns the NGOffsetMapping object when the current text is laid out with
-  // LayoutNG.
-  // Note that the text can be in legacy layout even when LayoutNG is enabled,
-  // so we can't simply check the RuntimeEnabledFeature.
-  const NGOffsetMapping* GetNGOffsetMapping() const;
-
   bool CanBeSelectionLeafInternal() const final { return true; }
 
  private:
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
index ecd1ec6..6a62e24ef 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
@@ -145,6 +145,61 @@
             GetBasicText()->ContainsOnlyWhitespaceOrNbsp());
 }
 
+struct NGOffsetMappingTestData {
+  const char* text;
+  unsigned dom_start;
+  unsigned dom_end;
+  bool success;
+  unsigned text_start;
+  unsigned text_end;
+} offset_mapping_test_data[] = {
+    {"<div id=target> a  b  </div>", 0, 1, true, 0, 0},
+    {"<div id=target> a  b  </div>", 1, 2, true, 0, 1},
+    {"<div id=target> a  b  </div>", 2, 3, true, 1, 2},
+    {"<div id=target> a  b  </div>", 2, 4, true, 1, 2},
+    {"<div id=target> a  b  </div>", 2, 5, true, 1, 3},
+    {"<div id=target> a  b  </div>", 3, 4, true, 2, 2},
+    {"<div id=target> a  b  </div>", 3, 5, true, 2, 3},
+    {"<div id=target> a  b  </div>", 5, 6, true, 3, 3},
+    {"<div id=target> a  b  </div>", 5, 7, true, 3, 3},
+    {"<div id=target> a  b  </div>", 6, 7, true, 3, 3},
+    {"<div>a <span id=target> </span>b</div>", 0, 1, false, 0, 1}};
+
+std::ostream& operator<<(std::ostream& out, NGOffsetMappingTestData data) {
+  return out << "\"" << data.text << "\" " << data.dom_start << ","
+             << data.dom_end << " => " << (data.success ? "true " : "false ")
+             << data.text_start << "," << data.text_end;
+}
+
+class MapDOMOffsetToTextContentOffset
+    : public LayoutTextTest,
+      private ScopedLayoutNGForTest,
+      public ::testing::WithParamInterface<NGOffsetMappingTestData> {
+ public:
+  MapDOMOffsetToTextContentOffset() : ScopedLayoutNGForTest(true) {}
+};
+
+INSTANTIATE_TEST_CASE_P(LayoutTextTest,
+                        MapDOMOffsetToTextContentOffset,
+                        ::testing::ValuesIn(offset_mapping_test_data));
+
+TEST_P(MapDOMOffsetToTextContentOffset, Basic) {
+  const auto data = GetParam();
+  SetBodyInnerHTML(data.text);
+  LayoutText* layout_text = GetBasicText();
+  const NGOffsetMapping* mapping = layout_text->GetNGOffsetMapping();
+  ASSERT_TRUE(mapping);
+  unsigned start = data.dom_start;
+  unsigned end = data.dom_end;
+  bool success =
+      layout_text->MapDOMOffsetToTextContentOffset(*mapping, &start, &end);
+  EXPECT_EQ(data.success, success);
+  if (success) {
+    EXPECT_EQ(data.text_start, start);
+    EXPECT_EQ(data.text_end, end);
+  }
+}
+
 TEST_P(ParameterizedLayoutTextTest, CaretMinMaxOffset) {
   SetBasicBody("foo");
   EXPECT_EQ(0, GetBasicText()->CaretMinOffset());
@@ -338,6 +393,41 @@
   EXPECT_TRUE(GetBasicText()->IsAfterNonCollapsedCharacter(1));
 }
 
+TEST_P(ParameterizedLayoutTextTest, GetUpperLeftCorner) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      width: 5em;
+    }
+    </style>
+    <div>12345 123<span id="target">45</span></div>
+  )HTML");
+  LayoutText* layout_text = GetLayoutTextById("target");
+  Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
+  EXPECT_TRUE(upper_left.has_value());
+  EXPECT_EQ(FloatPoint(30, 10), upper_left.value());
+}
+
+TEST_P(ParameterizedLayoutTextTest, GetUpperLeftCornerVLR) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      height: 5em;
+      writing-mode: vertical-lr;
+    }
+    </style>
+    <div>12345 123<span id="target">45</span></div>
+  )HTML");
+  LayoutText* layout_text = GetLayoutTextById("target");
+  Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
+  EXPECT_TRUE(upper_left.has_value());
+  EXPECT_EQ(FloatPoint(10, 30), upper_left.value());
+}
+
 TEST_P(ParameterizedLayoutTextTest, LinesBoundingBox) {
   LoadAhem();
   SetBasicBody(
diff --git a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.cc b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.cc
index 27230739..399a2e1 100644
--- a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.cc
+++ b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.cc
@@ -4,6 +4,7 @@
 
 #include "core/layout/ng/geometry/ng_physical_offset_rect.h"
 
+#include "platform/geometry/FloatRect.h"
 #include "platform/geometry/LayoutRect.h"
 #include "platform/wtf/text/WTFString.h"
 
@@ -42,6 +43,10 @@
   return {offset.left, offset.top, size.width, size.height};
 }
 
+FloatRect NGPhysicalOffsetRect::ToFloatRect() const {
+  return {offset.left, offset.top, size.width, size.height};
+}
+
 String NGPhysicalOffsetRect::ToString() const {
   return String::Format("%s,%s %sx%s", offset.left.ToString().Ascii().data(),
                         offset.top.ToString().Ascii().data(),
diff --git a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.h b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.h
index 278c024..859e824 100644
--- a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.h
+++ b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset_rect.h
@@ -12,6 +12,7 @@
 
 namespace blink {
 
+class FloatRect;
 class LayoutRect;
 
 // NGPhysicalOffsetRect is the position and size of a rect (typically a
@@ -39,6 +40,7 @@
   // logical/physical distinctions.
   explicit NGPhysicalOffsetRect(const LayoutRect&);
   LayoutRect ToLayoutRect() const;
+  FloatRect ToFloatRect() const;
 
   String ToString() const;
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
index 40f75230..339710d 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
@@ -7,6 +7,7 @@
 #include "core/dom/Node.h"
 #include "core/editing/PositionWithAffinity.h"
 #include "core/layout/LayoutTextFragment.h"
+#include "core/layout/ng/geometry/ng_logical_rect.h"
 #include "core/layout/ng/geometry/ng_physical_offset_rect.h"
 #include "core/layout/ng/inline/ng_line_height_metrics.h"
 #include "core/layout/ng/inline/ng_offset_mapping.h"
@@ -14,6 +15,40 @@
 
 namespace blink {
 
+NGPhysicalOffsetRect NGPhysicalTextFragment::LocalRect(
+    unsigned start_offset,
+    unsigned end_offset) const {
+  DCHECK_LE(start_offset, end_offset);
+  DCHECK_GE(start_offset, start_offset_);
+  DCHECK_LE(end_offset, end_offset_);
+
+  if (UNLIKELY(!shape_result_)) {
+    DCHECK(IsFlowControl());
+    DCHECK_EQ(Length(), 1u);
+    return {{}, Size()};
+  }
+
+  if (UNLIKELY(IsRtl(shape_result_->Direction())))
+    std::swap(start_offset, end_offset);
+  LayoutUnit start_position = LayoutUnit::FromFloatFloor(
+      shape_result_->PositionForOffset(start_offset - start_offset_));
+  LayoutUnit end_position = LayoutUnit::FromFloatCeil(
+      shape_result_->PositionForOffset(end_offset - start_offset_));
+  DCHECK_GE(end_position, start_position);
+  LayoutUnit inline_size = end_position - start_position;
+  switch (LineOrientation()) {
+    case NGLineOrientation::kHorizontal:
+      return {{start_position, LayoutUnit()}, {inline_size, Size().height}};
+    case NGLineOrientation::kClockWiseVertical:
+      return {{LayoutUnit(), start_position}, {Size().width, inline_size}};
+    case NGLineOrientation::kCounterClockWiseVertical:
+      return {{LayoutUnit(), Size().height - end_position},
+              {Size().width, inline_size}};
+  }
+  NOTREACHED();
+  return {};
+}
+
 NGPhysicalOffsetRect NGPhysicalTextFragment::SelfVisualRect() const {
   if (!shape_result_)
     return {};
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
index d1f5e76d..923031f3 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
@@ -105,6 +105,11 @@
     return IsHorizontal() ? kAlphabeticBaseline : kIdeographicBaseline;
   }
 
+  // The layout box of text in (start, end) range in local coordinate.
+  // Start and end offsets must be between StartOffset() and EndOffset().
+  NGPhysicalOffsetRect LocalRect(unsigned start_offset,
+                                 unsigned end_offset) const;
+
   // The visual bounding box that includes glpyh bounding box and CSS
   // properties, in local coordinates.
   NGPhysicalOffsetRect SelfVisualRect() const;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment_test.cc
index 7dac624..fc37fb0 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment_test.cc
@@ -4,6 +4,7 @@
 
 #include "core/layout/ng/inline/ng_physical_text_fragment.h"
 
+#include "core/layout/ng/geometry/ng_logical_rect.h"
 #include "core/layout/ng/inline/ng_inline_fragment_traversal.h"
 #include "core/layout/ng/ng_layout_test.h"
 #include "core/layout/ng/ng_physical_box_fragment.h"
@@ -36,6 +37,84 @@
   }
 };
 
+TEST_F(NGPhysicalTextFragmentTest, LocalRect) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      width: 5em;
+    }
+    </style>
+    <div id=container>01234 67890</div>
+  )HTML");
+  auto text_fragments = CollectTextFragmentsInContainer("container");
+  ASSERT_EQ(2u, text_fragments.size());
+  EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(20), LayoutUnit(0)},
+                                 {LayoutUnit(20), LayoutUnit(10)}),
+            text_fragments[1]->LocalRect(8, 10));
+}
+
+TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      width: 10em;
+      direction: rtl;
+      unicode-bidi: bidi-override;
+    }
+    </style>
+    <div id=container>0123456789 123456789</div>
+  )HTML");
+  auto text_fragments = CollectTextFragmentsInContainer("container");
+  ASSERT_EQ(2u, text_fragments.size());
+  // The 2nd line starts at 12, because the div has a bidi-control.
+  EXPECT_EQ(12u, text_fragments[1]->StartOffset());
+  EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(50), LayoutUnit(0)},
+                                 {LayoutUnit(20), LayoutUnit(10)}),
+            text_fragments[1]->LocalRect(14, 16));
+}
+
+TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      height: 5em;
+      writing-mode: vertical-lr;
+    }
+    </style>
+    <div id=container>01234 67890</div>
+  )HTML");
+  auto text_fragments = CollectTextFragmentsInContainer("container");
+  ASSERT_EQ(2u, text_fragments.size());
+  EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(0), LayoutUnit(20)},
+                                 {LayoutUnit(10), LayoutUnit(20)}),
+            text_fragments[1]->LocalRect(8, 10));
+}
+
+TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    div {
+      font: 10px/1 Ahem;
+      height: 5em;
+      writing-mode: vertical-rl;
+    }
+    </style>
+    <div id=container>01234 67890</div>
+  )HTML");
+  auto text_fragments = CollectTextFragmentsInContainer("container");
+  ASSERT_EQ(2u, text_fragments.size());
+  EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(0), LayoutUnit(20)},
+                                 {LayoutUnit(10), LayoutUnit(20)}),
+            text_fragments[1]->LocalRect(8, 10));
+}
+
 TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) {
   SetBodyInnerHTML("<div id=div>text</div>");
 
diff --git a/third_party/WebKit/Source/core/loader/BaseFetchContext.h b/third_party/WebKit/Source/core/loader/BaseFetchContext.h
index 66addb8..fc53768 100644
--- a/third_party/WebKit/Source/core/loader/BaseFetchContext.h
+++ b/third_party/WebKit/Source/core/loader/BaseFetchContext.h
@@ -50,6 +50,7 @@
   void Trace(blink::Visitor*) override;
 
   virtual KURL GetSiteForCookies() const = 0;
+  virtual SubresourceFilter* GetSubresourceFilter() const = 0;
   virtual void CountUsage(WebFeature) const = 0;
   virtual void CountDeprecation(WebFeature) const = 0;
 
@@ -62,7 +63,6 @@
  protected:
   // Used for security checks.
   virtual bool AllowScriptFromSource(const KURL&) const = 0;
-  virtual SubresourceFilter* GetSubresourceFilter() const = 0;
 
   // Note: subclasses are expected to override following methods.
   // Used in the default implementation for CanRequest, CanFollowRedirect
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 673c9a2..dc3989c 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -74,7 +74,8 @@
 namespace {
 
 // Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0
-String CreateAccessControlRequestHeadersHeader(const HTTPHeaderMap& headers) {
+AtomicString CreateAccessControlRequestHeadersHeader(
+    const HTTPHeaderMap& headers) {
   Vector<String> filtered_headers;
   for (const auto& header : headers) {
     // Exclude CORS-safelisted headers.
@@ -102,7 +103,7 @@
     header_buffer.Append(header);
   }
 
-  return header_buffer.ToString();
+  return header_buffer.ToAtomicString();
 }
 
 class EmptyDataHandle final : public WebDataConsumerHandle {
@@ -165,45 +166,51 @@
 }
 
 // static
-WebURLRequest DocumentThreadableLoader::CreateAccessControlPreflightRequest(
-    const WebURLRequest& request) {
+std::unique_ptr<ResourceRequest>
+DocumentThreadableLoader::CreateAccessControlPreflightRequest(
+    const ResourceRequest& request,
+    const SecurityOrigin* origin) {
   const KURL& request_url = request.Url();
 
   DCHECK(request_url.User().IsEmpty());
   DCHECK(request_url.Pass().IsEmpty());
 
-  WebURLRequest preflight_request(request_url);
-  preflight_request.SetHTTPMethod(HTTPNames::OPTIONS);
-  preflight_request.SetHTTPHeaderField(HTTPNames::Access_Control_Request_Method,
-                                       request.HttpMethod());
-  preflight_request.SetPriority(request.GetPriority());
-  preflight_request.SetRequestContext(request.GetRequestContext());
-  preflight_request.SetFetchCredentialsMode(
+  std::unique_ptr<ResourceRequest> preflight_request =
+      std::make_unique<ResourceRequest>(request_url);
+  preflight_request->SetHTTPMethod(HTTPNames::OPTIONS);
+  preflight_request->SetHTTPHeaderField(
+      HTTPNames::Access_Control_Request_Method, request.HttpMethod());
+  preflight_request->SetPriority(request.Priority());
+  preflight_request->SetRequestContext(request.GetRequestContext());
+  preflight_request->SetFetchCredentialsMode(
       network::mojom::FetchCredentialsMode::kOmit);
-  preflight_request.SetSkipServiceWorker(true);
-  preflight_request.SetHTTPReferrer(request.HttpHeaderField(HTTPNames::Referer),
-                                    request.GetReferrerPolicy());
+  preflight_request->SetSkipServiceWorker(true);
+  preflight_request->SetHTTPReferrer(
+      Referrer(request.HttpReferrer(), request.GetReferrerPolicy()));
 
   if (request.IsExternalRequest()) {
-    preflight_request.SetHTTPHeaderField(
+    preflight_request->SetHTTPHeaderField(
         HTTPNames::Access_Control_Request_External, "true");
   }
 
-  String request_headers = CreateAccessControlRequestHeadersHeader(
-      request.ToResourceRequest().HttpHeaderFields());
+  const AtomicString request_headers =
+      CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields());
   if (request_headers != g_null_atom) {
-    preflight_request.SetHTTPHeaderField(
+    preflight_request->SetHTTPHeaderField(
         HTTPNames::Access_Control_Request_Headers, request_headers);
   }
 
+  if (origin)
+    preflight_request->SetHTTPOrigin(origin);
+
   return preflight_request;
 }
 
 // static
-WebURLRequest
+std::unique_ptr<ResourceRequest>
 DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
-    const WebURLRequest& request) {
-  return CreateAccessControlPreflightRequest(request);
+    const ResourceRequest& request) {
+  return CreateAccessControlPreflightRequest(request, nullptr);
 }
 
 // static
@@ -456,16 +463,8 @@
 void DocumentThreadableLoader::LoadPreflightRequest(
     const ResourceRequest& actual_request,
     const ResourceLoaderOptions& actual_options) {
-  WebURLRequest web_url_request = CreateAccessControlPreflightRequest(
-      WrappedResourceRequest(actual_request));
-
-  ResourceRequest& preflight_request =
-      web_url_request.ToMutableResourceRequest();
-
-  // TODO(tyoshino): Call PrepareCrossOriginRequest(preflight_request) to also
-  // set the referrer header.
-  if (GetSecurityOrigin())
-    preflight_request.SetHTTPOrigin(GetSecurityOrigin());
+  std::unique_ptr<ResourceRequest> preflight_request =
+      CreateAccessControlPreflightRequest(actual_request, GetSecurityOrigin());
 
   actual_request_ = actual_request;
   actual_options_ = actual_options;
@@ -479,7 +478,7 @@
   // Create a ResourceLoaderOptions for preflight.
   ResourceLoaderOptions preflight_options = actual_options;
 
-  LoadRequest(preflight_request, preflight_options);
+  LoadRequest(*preflight_request, preflight_options);
 }
 
 void DocumentThreadableLoader::MakeCrossOriginAccessRequest(
@@ -1345,10 +1344,10 @@
     case network::mojom::FetchCredentialsMode::kOmit:
       break;
     case network::mojom::FetchCredentialsMode::kSameOrigin:
-      // TODO(tyoshino): It's wrong to use |cors_flag| here. Fix it to use the
+      // TODO(toyoshim): It's wrong to use |cors_flag| here. Fix it to use the
       // response tainting.
       //
-      // TODO(tyoshino): The credentials mode must work even when the "no-cors"
+      // TODO(toyoshim): The credentials mode must work even when the "no-cors"
       // mode is in use. See the following issues:
       // - https://github.com/whatwg/fetch/issues/130
       // - https://github.com/whatwg/fetch/issues/169
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index 3d73ff21..c289d30 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -68,8 +68,8 @@
                                         const ResourceLoaderOptions&);
 
   // Exposed for testing. Code outside this class should not call this function.
-  static WebURLRequest CreateAccessControlPreflightRequestForTesting(
-      const WebURLRequest&);
+  static std::unique_ptr<ResourceRequest>
+  CreateAccessControlPreflightRequestForTesting(const ResourceRequest&);
 
   static DocumentThreadableLoader* Create(ThreadableLoadingContext&,
                                           ThreadableLoaderClient*,
@@ -90,8 +90,9 @@
  private:
   enum BlockingBehavior { kLoadSynchronously, kLoadAsynchronously };
 
-  static WebURLRequest CreateAccessControlPreflightRequest(
-      const WebURLRequest&);
+  static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest(
+      const ResourceRequest&,
+      const SecurityOrigin*);
 
   DocumentThreadableLoader(ThreadableLoadingContext&,
                            ThreadableLoaderClient*,
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoaderTest.cpp
index 2767831..fcdd750b 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoaderTest.cpp
@@ -14,77 +14,77 @@
 namespace {
 
 TEST(DocumentThreadableLoaderCreatePreflightRequestTest, LexicographicalOrder) {
-  WebURLRequest request;
+  ResourceRequest request;
   request.AddHTTPHeaderField("Orange", "Orange");
   request.AddHTTPHeaderField("Apple", "Red");
   request.AddHTTPHeaderField("Kiwifruit", "Green");
   request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
   request.AddHTTPHeaderField("Strawberry", "Red");
 
-  WebURLRequest preflight =
+  std::unique_ptr<ResourceRequest> preflight =
       DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
           request);
 
   EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry",
-            preflight.HttpHeaderField("Access-Control-Request-Headers"));
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
 }
 
 TEST(DocumentThreadableLoaderCreatePreflightRequestTest, ExcludeSimpleHeaders) {
-  WebURLRequest request;
+  ResourceRequest request;
   request.AddHTTPHeaderField("Accept", "everything");
   request.AddHTTPHeaderField("Accept-Language", "everything");
   request.AddHTTPHeaderField("Content-Language", "everything");
   request.AddHTTPHeaderField("Save-Data", "on");
 
-  WebURLRequest preflight =
+  std::unique_ptr<ResourceRequest> preflight =
       DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
           request);
 
   // Do not emit empty-valued headers; an empty list of non-"CORS safelisted"
   // request headers should cause "Access-Control-Request-Headers:" to be
   // left out in the preflight request.
-  EXPECT_EQ(WebString(g_null_atom),
-            preflight.HttpHeaderField("Access-Control-Request-Headers"));
+  EXPECT_EQ(g_null_atom,
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
 }
 
 TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
      ExcludeSimpleContentTypeHeader) {
-  WebURLRequest request;
+  ResourceRequest request;
   request.AddHTTPHeaderField("Content-Type", "text/plain");
 
-  WebURLRequest preflight =
+  std::unique_ptr<ResourceRequest> preflight =
       DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
           request);
 
   // Empty list also; see comment in test above.
-  EXPECT_EQ(WebString(g_null_atom),
-            preflight.HttpHeaderField("Access-Control-Request-Headers"));
+  EXPECT_EQ(g_null_atom,
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
 }
 
 TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
      IncludeNonSimpleHeader) {
-  WebURLRequest request;
+  ResourceRequest request;
   request.AddHTTPHeaderField("X-Custom-Header", "foobar");
 
-  WebURLRequest preflight =
+  std::unique_ptr<ResourceRequest> preflight =
       DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
           request);
 
   EXPECT_EQ("x-custom-header",
-            preflight.HttpHeaderField("Access-Control-Request-Headers"));
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
 }
 
 TEST(DocumentThreadableLoaderCreatePreflightRequestTest,
      IncludeNonSimpleContentTypeHeader) {
-  WebURLRequest request;
+  ResourceRequest request;
   request.AddHTTPHeaderField("Content-Type", "application/octet-stream");
 
-  WebURLRequest preflight =
+  std::unique_ptr<ResourceRequest> preflight =
       DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting(
           request);
 
   EXPECT_EQ("content-type",
-            preflight.HttpHeaderField("Access-Control-Request-Headers"));
+            preflight->HttpHeaderField("Access-Control-Request-Headers"));
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index e869abcb..685e5c3 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -333,6 +333,13 @@
   return document->SiteForCookies();
 }
 
+SubresourceFilter* FrameFetchContext::GetSubresourceFilter() const {
+  if (IsDetached())
+    return nullptr;
+  DocumentLoader* document_loader = MasterDocumentLoader();
+  return document_loader ? document_loader->GetSubresourceFilter() : nullptr;
+}
+
 LocalFrame* FrameFetchContext::GetFrame() const {
   DCHECK(!IsDetached());
 
@@ -999,13 +1006,6 @@
   return true;
 }
 
-SubresourceFilter* FrameFetchContext::GetSubresourceFilter() const {
-  if (IsDetached())
-    return nullptr;
-  DocumentLoader* document_loader = MasterDocumentLoader();
-  return document_loader ? document_loader->GetSubresourceFilter() : nullptr;
-}
-
 bool FrameFetchContext::ShouldBlockRequestByInspector(const KURL& url) const {
   if (IsDetached())
     return false;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.h b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
index 6382c786..559a6c26 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.h
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
@@ -197,8 +197,8 @@
 
   // BaseFetchContext overrides:
   KURL GetSiteForCookies() const override;
-  bool AllowScriptFromSource(const KURL&) const override;
   SubresourceFilter* GetSubresourceFilter() const override;
+  bool AllowScriptFromSource(const KURL&) const override;
   bool ShouldBlockRequestByInspector(const KURL&) const override;
   void DispatchDidBlockRequest(const ResourceRequest&,
                                const FetchInitiatorInfo&,
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
index 3a7bcf8..1292448 100644
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
@@ -109,6 +109,10 @@
   return web_context_->SiteForCookies();
 }
 
+SubresourceFilter* WorkerFetchContext::GetSubresourceFilter() const {
+  return subresource_filter_.Get();
+}
+
 bool WorkerFetchContext::AllowScriptFromSource(const KURL&) const {
   // Currently we don't use WorkerFetchContext for loading scripts. So this
   // method must not be called.
@@ -119,10 +123,6 @@
   return false;
 }
 
-SubresourceFilter* WorkerFetchContext::GetSubresourceFilter() const {
-  return subresource_filter_.Get();
-}
-
 bool WorkerFetchContext::ShouldBlockRequestByInspector(const KURL& url) const {
   bool should_block_request = false;
   probe::shouldBlockRequest(global_scope_, url, &should_block_request);
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.h b/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
index cc3bec1..81780a3f5 100644
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
@@ -35,8 +35,8 @@
 
   // BaseFetchContext implementation:
   KURL GetSiteForCookies() const override;
-  bool AllowScriptFromSource(const KURL&) const override;
   SubresourceFilter* GetSubresourceFilter() const override;
+  bool AllowScriptFromSource(const KURL&) const override;
   bool ShouldBlockRequestByInspector(const KURL&) const override;
   void DispatchDidBlockRequest(const ResourceRequest&,
                                const FetchInitiatorInfo&,
diff --git a/third_party/WebKit/Source/core/messaging/BlinkTransferableMessage.cpp b/third_party/WebKit/Source/core/messaging/BlinkTransferableMessage.cpp
index 5a4b58c..3a959af 100644
--- a/third_party/WebKit/Source/core/messaging/BlinkTransferableMessage.cpp
+++ b/third_party/WebKit/Source/core/messaging/BlinkTransferableMessage.cpp
@@ -22,7 +22,7 @@
   BlinkTransferableMessage result;
   result.message = SerializedScriptValue::Create(
       reinterpret_cast<const char*>(message.encoded_message.data()),
-      message.encoded_message.length());
+      message.encoded_message.size());
   for (auto& blob : message.blobs) {
     result.message->BlobDataHandles().Set(
         WebString::FromUTF8(blob->uuid),
diff --git a/third_party/WebKit/Source/core/paint/ng/ng_paint_fragment.h b/third_party/WebKit/Source/core/paint/ng/ng_paint_fragment.h
index f3629dc9..45e2ba2 100644
--- a/third_party/WebKit/Source/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/WebKit/Source/core/paint/ng/ng_paint_fragment.h
@@ -113,6 +113,8 @@
       return is_in_layout_ng_inline_formatting_context_;
     }
 
+    bool IsEmpty() const { return !first_; }
+
     class iterator {
      public:
       explicit iterator(NGPaintFragment* first) : current_(first) {}
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index f6f9afe4..6df54aa 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -2117,7 +2117,6 @@
 }
 
 void ComputedStyle::CopyChildDependentFlagsFrom(const ComputedStyle& other) {
-  SetEmptyState(other.EmptyState());
   if (other.HasExplicitlyInheritedProperties())
     SetHasExplicitlyInheritedProperties();
 }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 58b462c..eb923e8 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1043,7 +1043,7 @@
   bool InheritedDataShared(const ComputedStyle&) const;
 
   bool HasChildDependentFlags() const {
-    return EmptyState() || HasExplicitlyInheritedProperties();
+    return HasExplicitlyInheritedProperties();
   }
   void CopyChildDependentFlagsFrom(const ComputedStyle&);
 
@@ -1111,11 +1111,6 @@
   void AddCallbackSelector(const String& selector);
 
   // Non-property flags.
-  void SetEmptyState(bool b) {
-    SetUnique();
-    SetEmptyStateInternal(b);
-  }
-
   CORE_EXPORT void SetTextAutosizingMultiplier(float);
 
   // Column utility functions.
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 3b50610..5e1a4c7a 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2813,9 +2813,9 @@
     scoped_refptr<SerializedScriptValue> value) const {
   base::span<const uint8_t> span = value->GetWireData();
   DOMArrayBuffer* buffer =
-      DOMArrayBuffer::CreateUninitializedOrNull(span.length(), sizeof(uint8_t));
+      DOMArrayBuffer::CreateUninitializedOrNull(span.size(), sizeof(uint8_t));
   if (buffer)
-    memcpy(buffer->Data(), span.data(), span.length());
+    memcpy(buffer->Data(), span.data(), span.size());
   return buffer;
 }
 
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 8148d4cd..83d9438 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -740,7 +740,6 @@
   "front_end/timeline/timelinePanel.css",
   "front_end/timeline/TimelinePanel.js",
   "front_end/timeline/timelineStatusDialog.css",
-  "front_end/timeline/TimelineTreeModeView.js",
   "front_end/timeline/TimelineTreeView.js",
   "front_end/timeline/TimelineUIUtils.js",
   "front_end/timeline/PerformanceMonitor.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotDataGrids.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotDataGrids.js
index b2cafd4..0e8597e9 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotDataGrids.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotDataGrids.js
@@ -440,6 +440,13 @@
     return new Promise(resolve => {
       console.assert(!this._scrollToResolveCallback);
       this._scrollToResolveCallback = resolve.bind(null, node);
+      // Still resolve the promise if it does not scroll for some reason.
+      this.scrollContainer.window().requestAnimationFrame(() => {
+        if (!this._scrollToResolveCallback)
+          return;
+        this._scrollToResolveCallback();
+        this._scrollToResolveCallback = null;
+      });
     });
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
index 7bbd007..cf071cb 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -342,7 +342,7 @@
     this._searchableView.updateSearchMatchesCount(this._searchResults.length);
     if (this._searchResults.length)
       this._currentSearchResultIndex = nextQuery.jumpBackwards ? this._searchResults.length - 1 : 0;
-    return this._jumpToSearchResult(this._currentSearchResultIndex);
+    await this._jumpToSearchResult(this._currentSearchResultIndex);
   }
 
   /**
@@ -372,6 +372,8 @@
    */
   async _jumpToSearchResult(searchResultIndex) {
     this._searchableView.updateCurrentMatchIndex(searchResultIndex);
+    if (searchResultIndex === -1)
+      return;
     const node = await this._dataGrid.revealObjectByHeapSnapshotId(String(this._searchResults[searchResultIndex]));
     this._selectRevealedNode(node);
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
index a28a50d..de3964e 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
@@ -114,6 +114,7 @@
 
 .profile-launcher-view-content {
     padding: 10px 16px;
+    overflow: auto;
 }
 
 .profile-launcher-view-content h1 {
diff --git a/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js
index 8818bf1..c146b19 100644
--- a/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js
@@ -275,6 +275,7 @@
    * @param {string} query
    */
   setQuery(query) {
+    this._prompt.focus();
     this._prompt.setText(query);
     this._queryChanged();
     this._prompt.autoCompleteSoon(true);
@@ -295,6 +296,7 @@
     }
     if (!completion)
       return false;
+    this._prompt.focus();
     this._prompt.setText(completion);
     this._prompt.setDOMSelection(userEnteredText.length, completion.length);
     this._scheduleFilter();
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeModeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeModeView.js
deleted file mode 100644
index d683e64..0000000
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeModeView.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @implements {Timeline.TimelineModeView}
- */
-Timeline.TimelineTreeModeView = class extends UI.VBox {
-  /**
-   * @param {!Timeline.TimelineModeViewDelegate} delegate
-   * @param {!Timeline.TimelineTreeView} innerTreeView
-   */
-  constructor(delegate, innerTreeView) {
-    super();
-    this._treeView = innerTreeView;
-    this._treeView.show(this.element);
-  }
-
-  /**
-   * @override
-   * @return {?Element}
-   */
-  resizerElement() {
-    return null;
-  }
-
-  /**
-   * @override
-   * @param {?SDK.TracingModel.Event} event
-   */
-  highlightEvent(event) {
-  }
-
-  /**
-   * @override
-   * @param {?Timeline.PerformanceModel} model
-   */
-  setModel(model) {
-    this._treeView.setModel(model);
-  }
-
-  /**
-   * @override
-   */
-  setSelection() {
-  }
-
-  /**
-   * @override
-   * @param {number} startTime
-   * @param {number} endTime
-   */
-  setWindowTimes(startTime, endTime) {
-    this._treeView.setRange(startTime, endTime);
-  }
-
-  /**
-   * @override
-   * @return {!UI.Widget}
-   */
-  view() {
-    return this;
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/module.json b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
index c52c1455..0266b35 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
@@ -255,7 +255,6 @@
         "TimelineFlameChartNetworkDataProvider.js",
         "TimelineFlameChartView.js",
         "TimelineHistoryManager.js",
-        "TimelineTreeModeView.js",
         "TimelineTreeView.js",
         "EventsTimelineTreeView.js",
         "TimelineUIUtils.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js b/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js
index 0ee76d8..a0fa78f 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js
@@ -295,13 +295,8 @@
   _updateSearchNavigationButtonState(enabled) {
     this._replaceButtonElement.disabled = !enabled;
     this._replaceAllButtonElement.disabled = !enabled;
-    if (enabled) {
-      this._searchNavigationPrevElement.classList.add('enabled');
-      this._searchNavigationNextElement.classList.add('enabled');
-    } else {
-      this._searchNavigationPrevElement.classList.remove('enabled');
-      this._searchNavigationNextElement.classList.remove('enabled');
-    }
+    this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
+    this._searchNavigationNextElement.classList.toggle('enabled', enabled);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
index 55906f0..7aac5f2e 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
@@ -174,9 +174,14 @@
     this.clearAutocomplete();
     this._element.textContent = text;
     this._previousText = this.text();
+    if (this._element.hasFocus()) {
+      this.moveCaretToEndOfPrompt();
+      this._element.scrollIntoView();
+    }
+  }
 
-    this.moveCaretToEndOfPrompt();
-    this._element.scrollIntoView();
+  focus() {
+    this._element.focus();
   }
 
   /**
diff --git a/third_party/WebKit/Source/modules/animationworklet/WorkletAnimation.cpp b/third_party/WebKit/Source/modules/animationworklet/WorkletAnimation.cpp
index 85f7608..e7cfa7ca 100644
--- a/third_party/WebKit/Source/modules/animationworklet/WorkletAnimation.cpp
+++ b/third_party/WebKit/Source/modules/animationworklet/WorkletAnimation.cpp
@@ -289,7 +289,7 @@
   CompositorAnimations::AttachCompositedLayers(target,
                                                compositor_animation_.get());
 
-  double start_time = std::numeric_limits<double>::quiet_NaN();
+  WTF::Optional<double> start_time = WTF::nullopt;
   double time_offset = 0;
   int group = 0;
 
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.cpp
index ecd9a6ff..d9ef4097 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.cpp
@@ -41,6 +41,11 @@
 
 BackgroundFetchBridge::~BackgroundFetchBridge() = default;
 
+void BackgroundFetchBridge::GetIconDisplaySize(
+    GetIconDisplaySizeCallback callback) {
+  GetService()->GetIconDisplaySize(std::move(callback));
+}
+
 void BackgroundFetchBridge::Fetch(
     const String& developer_id,
     Vector<WebServiceWorkerRequest> requests,
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.h b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.h
index 13fed0e..f3eb7f8 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.h
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchBridge.h
@@ -39,6 +39,7 @@
   using RegistrationCallback =
       base::OnceCallback<void(mojom::blink::BackgroundFetchError,
                               BackgroundFetchRegistration*)>;
+  using GetIconDisplaySizeCallback = base::OnceCallback<void(const WebSize&)>;
   using UpdateUICallback =
       base::OnceCallback<void(mojom::blink::BackgroundFetchError)>;
 
@@ -55,6 +56,9 @@
              const SkBitmap& icon,
              RegistrationCallback);
 
+  // Gets the size of the icon to be displayed in Background Fetch UI.
+  void GetIconDisplaySize(GetIconDisplaySizeCallback);
+
   // Updates the user interface for the Background Fetch identified by
   // |unique_id| with the updated |title|. Will invoke the |callback| when the
   // interface has been requested to update.
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.cpp
index 7ecd13e..5b4727b 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.cpp
@@ -6,14 +6,17 @@
 
 #include "core/dom/ExecutionContext.h"
 #include "core/loader/ThreadableLoader.h"
+#include "modules/background_fetch/BackgroundFetchBridge.h"
 #include "modules/background_fetch/IconDefinition.h"
 #include "platform/graphics/ColorBehavior.h"
+#include "platform/heap/HeapAllocator.h"
 #include "platform/image-decoders/ImageDecoder.h"
 #include "platform/image-decoders/ImageFrame.h"
 #include "platform/loader/fetch/ResourceLoaderOptions.h"
 #include "platform/loader/fetch/ResourceRequest.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/wtf/Threading.h"
+#include "public/platform/WebSize.h"
 #include "public/platform/WebURLRequest.h"
 #include "skia/ext/image_operations.h"
 
@@ -32,14 +35,28 @@
 }
 
 // TODO(nator): Add functionality to select which icon to load.
-void BackgroundFetchIconLoader::Start(ExecutionContext* execution_context,
+void BackgroundFetchIconLoader::Start(BackgroundFetchBridge* bridge,
+                                      ExecutionContext* execution_context,
                                       HeapVector<IconDefinition> icons,
                                       IconCallback icon_callback) {
   DCHECK(!stopped_);
   DCHECK_GE(icons.size(), 1u);
-  icons_ = std::move(icons);
+  DCHECK(bridge);
 
-  if (!icons_[0].hasSrc()) {
+  icons_ = std::move(icons);
+  bridge->GetIconDisplaySize(
+      WTF::Bind(&BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon,
+                WrapWeakPersistent(this), WrapWeakPersistent(execution_context),
+                std::move(icon_callback)));
+}
+
+void BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon(
+    ExecutionContext* execution_context,
+    IconCallback icon_callback,
+    const WebSize& icon_display_size_pixels) {
+  // TODO(nator): Pick the appropriate icon based on display size instead,
+  // and resize it, if needed.
+  if (icon_display_size_pixels.IsEmpty() || !icons_[0].hasSrc()) {
     std::move(icon_callback).Run(SkBitmap());
     return;
   }
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.h b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.h
index d1df27c..17fcd1f 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.h
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoader.h
@@ -16,7 +16,9 @@
 
 namespace blink {
 
+class BackgroundFetchBridge;
 class IconDefinition;
+struct WebSize;
 
 class MODULES_EXPORT BackgroundFetchIconLoader final
     : public GarbageCollectedFinalized<BackgroundFetchIconLoader>,
@@ -35,7 +37,10 @@
 
   // Asynchronously download an icon from the given url, decodes the loaded
   // data, and passes the bitmap to the given callback.
-  void Start(ExecutionContext*, HeapVector<IconDefinition>, IconCallback);
+  void Start(BackgroundFetchBridge*,
+             ExecutionContext*,
+             HeapVector<IconDefinition>,
+             IconCallback);
 
   // Cancels the pending load, if there is one. The |icon_callback_| will not
   // be run.
@@ -54,8 +59,15 @@
   }
 
  private:
+  friend class BackgroundFetchIconLoaderTest;
   void RunCallbackWithEmptyBitmap();
 
+  // Callback for BackgroundFetchBridge::GetIconDisplaySize()
+  void DidGetIconDisplaySizeIfSoLoadIcon(
+      ExecutionContext*,
+      IconCallback,
+      const WebSize& icon_display_size_pixels);
+
   bool stopped_ = false;
   scoped_refptr<SharedBuffer> data_;
   IconCallback icon_callback_;
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoaderTest.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoaderTest.cpp
index 49aa317..961500c 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoaderTest.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchIconLoaderTest.cpp
@@ -11,6 +11,7 @@
 #include "platform/testing/URLTestHelpers.h"
 #include "platform/testing/UnitTestHelpers.h"
 #include "platform/weborigin/KURL.h"
+#include "public/platform/WebSize.h"
 #include "public/platform/WebURL.h"
 #include "public/platform/WebURLLoaderMockFactory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -28,6 +29,8 @@
 constexpr char kBackgroundFetchImageLoaderBaseDir[] = "notifications/";
 constexpr char kBackgroundFetchImageLoaderIcon500x500[] = "500x500.png";
 
+}  // namespace
+
 class BackgroundFetchIconLoaderTest : public PageTestBase {
  public:
   BackgroundFetchIconLoaderTest() : loader_(new BackgroundFetchIconLoader()) {}
@@ -63,9 +66,11 @@
     icon.setType("image/png");
     icon.setSizes("500x500");
     HeapVector<IconDefinition> icons(1, icon);
-    loader_->Start(GetContext(), icons,
-                   Bind(&BackgroundFetchIconLoaderTest::IconLoaded,
-                        WTF::Unretained(this)));
+    loader_->icons_ = std::move(icons);
+    loader_->DidGetIconDisplaySizeIfSoLoadIcon(
+        GetContext(),
+        Bind(&BackgroundFetchIconLoaderTest::IconLoaded, WTF::Unretained(this)),
+        WebSize(192, 192));
   }
 
   ExecutionContext* GetContext() const { return &GetDocument(); }
@@ -85,5 +90,4 @@
   EXPECT_EQ(BackgroundFetchLoadState::kLoadSuccessful, loaded_);
 }
 
-}  // namespace
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
index 4ebe9e55..d222a65 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
@@ -261,7 +261,7 @@
       mojom::blink::BackgroundFetchOptions::From(options);
   if (options.icons().size()) {
     loader_->Start(
-        execution_context, options.icons(),
+        bridge_.Get(), execution_context, options.icons(),
         WTF::Bind(&BackgroundFetchManager::DidLoadIcons, WrapPersistent(this),
                   id, WTF::Passed(std::move(web_requests)),
                   std::move(options_ptr), WrapPersistent(resolver)));
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
index 945fa8d..38a0f2db 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
@@ -25,7 +25,7 @@
 
   scoped_refptr<SharedBuffer> idb_value_buffer = SharedBuffer::Create();
   idb_value_buffer->Append(reinterpret_cast<const char*>(ssv_wire_bytes.data()),
-                           ssv_wire_bytes.length());
+                           ssv_wire_bytes.size());
   std::unique_ptr<IDBValue> idb_value =
       IDBValue::Create(std::move(idb_value_buffer), Vector<WebBlobInfo>());
   idb_value->SetInjectedPrimaryKey(IDBKey::CreateNumber(42.0),
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
index 708a9028..687d6566 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
@@ -136,7 +136,7 @@
   DCHECK(owns_wire_bytes_) << __func__ << " called after TakeWireBytes()";
 #endif  // DCHECK_IS_ON()
 
-  unsigned wire_data_size = wire_data_.length();
+  unsigned wire_data_size = wire_data_.size();
   if (wire_data_size <= max_bytes)
     return false;
 
@@ -175,15 +175,14 @@
   if (wire_data_buffer_.IsEmpty()) {
     // The wire bytes are coming directly from the SSV's GetWireData() call.
     DCHECK_EQ(wire_data_.data(), serialized_value_->GetWireData().data());
-    DCHECK_EQ(wire_data_.length(), serialized_value_->GetWireData().length());
-    return SharedBuffer::Create(wire_data_.data(),
-                                static_cast<size_t>(wire_data_.length()));
+    DCHECK_EQ(wire_data_.size(), serialized_value_->GetWireData().size());
+    return SharedBuffer::Create(wire_data_.data(), wire_data_.size());
   }
 
   // The wire bytes are coming from wire_data_buffer_, so we can avoid a copy.
   DCHECK_EQ(wire_data_buffer_.data(),
             reinterpret_cast<const char*>(wire_data_.data()));
-  DCHECK_EQ(wire_data_buffer_.size(), wire_data_.length());
+  DCHECK_EQ(wire_data_buffer_.size(), wire_data_.size());
   return SharedBuffer::AdoptVector(wire_data_buffer_);
 }
 
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index c53a10d1..1bb0301 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -163,11 +163,14 @@
   if (media_element.FastHasAttribute(HTMLNames::disableremoteplaybackAttr))
     return false;
 
-  // Explicitly do not show cast button when the mediaControlsEnabled setting is
-  // false to make sure the overlay does not appear.
+  // Explicitly do not show cast button when:
+  // - the mediaControlsEnabled setting is false, to make sure the overlay does
+  //   not appear;
+  // - the immersiveModeEnabled setting is true.
   Document& document = media_element.GetDocument();
   if (document.GetSettings() &&
-      !document.GetSettings()->GetMediaControlsEnabled()) {
+      (!document.GetSettings()->GetMediaControlsEnabled() ||
+       document.GetSettings()->GetImmersiveModeEnabled())) {
     return false;
   }
 
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
index 6da8aba..ca3030e5 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
@@ -447,10 +447,13 @@
         break;
     }
   }
-  if (platform_settings.HasEchoCancellationValue()) {
-    settings.setEchoCancellation(
-        static_cast<bool>(platform_settings.echo_cancellation));
-  }
+
+  if (platform_settings.echo_cancellation)
+    settings.setEchoCancellation(*platform_settings.echo_cancellation);
+  if (platform_settings.auto_gain_control)
+    settings.setAutoGainControl(*platform_settings.auto_gain_control);
+  if (platform_settings.noise_supression)
+    settings.setNoiseSuppression(*platform_settings.noise_supression);
 
   if (image_capture_)
     image_capture_->GetMediaTrackSettings(settings);
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
index 0c21eaa..8cbdef9d 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackSettings.idl
@@ -15,6 +15,8 @@
     // long sampleRate;
     // long sampleSize;
     boolean echoCancellation;
+    boolean autoGainControl;
+    boolean noiseSuppression;
     // latency and channelCount are not implemented.
     // double latency;
     // long channelCount;
diff --git a/third_party/WebKit/Source/modules/peerconnection/BUILD.gn b/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
index 6c9d8ab5..7b463a4 100644
--- a/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
+++ b/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
@@ -50,5 +50,7 @@
     "RTCVoidRequestImpl.h",
     "RTCVoidRequestPromiseImpl.cpp",
     "RTCVoidRequestPromiseImpl.h",
+    "WebRTCStatsReportCallbackResolver.cpp",
+    "WebRTCStatsReportCallbackResolver.h",
   ]
 }
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
index 41452ed..a5a995a 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
@@ -83,6 +83,7 @@
 #include "modules/peerconnection/RTCTrackEvent.h"
 #include "modules/peerconnection/RTCVoidRequestImpl.h"
 #include "modules/peerconnection/RTCVoidRequestPromiseImpl.h"
+#include "modules/peerconnection/WebRTCStatsReportCallbackResolver.h"
 #include "modules/peerconnection/testing/InternalsRTCPeerConnection.h"
 #include "platform/InstanceCounters.h"
 #include "platform/bindings/Microtask.h"
@@ -416,35 +417,6 @@
   return rtc_offer_options;
 }
 
-// Helper class for
-// |RTCPeerConnection::getStats(ScriptState*, MediaStreamTrack*)|
-class WebRTCStatsReportCallbackResolver : public WebRTCStatsReportCallback {
- public:
-  // Takes ownership of |resolver|.
-  static std::unique_ptr<WebRTCStatsReportCallback> Create(
-      ScriptPromiseResolver* resolver) {
-    return std::unique_ptr<WebRTCStatsReportCallback>(
-        new WebRTCStatsReportCallbackResolver(resolver));
-  }
-
-  ~WebRTCStatsReportCallbackResolver() override {
-    DCHECK(
-        ExecutionContext::From(resolver_->GetScriptState())->IsContextThread());
-  }
-
- private:
-  explicit WebRTCStatsReportCallbackResolver(ScriptPromiseResolver* resolver)
-      : resolver_(resolver) {}
-
-  void OnStatsDelivered(std::unique_ptr<WebRTCStatsReport> report) override {
-    DCHECK(
-        ExecutionContext::From(resolver_->GetScriptState())->IsContextThread());
-    resolver_->Resolve(new RTCStatsReport(std::move(report)));
-  }
-
-  Persistent<ScriptPromiseResolver> resolver_;
-};
-
 bool FingerprintMismatch(String old_sdp, String new_sdp) {
   // Check special case of externally generated SDP without fingerprints.
   // It's impossible to generate a valid fingerprint without createOffer
diff --git a/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.cpp b/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.cpp
new file mode 100644
index 0000000..62b53c9e
--- /dev/null
+++ b/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.cpp
@@ -0,0 +1,30 @@
+#include "modules/peerconnection/WebRTCStatsReportCallbackResolver.h"
+
+#include "core/dom/ExecutionContext.h"
+
+namespace blink {
+
+// static
+std::unique_ptr<WebRTCStatsReportCallback>
+WebRTCStatsReportCallbackResolver::Create(ScriptPromiseResolver* resolver) {
+  return std::unique_ptr<WebRTCStatsReportCallback>(
+      new WebRTCStatsReportCallbackResolver(resolver));
+}
+
+WebRTCStatsReportCallbackResolver::WebRTCStatsReportCallbackResolver(
+    ScriptPromiseResolver* resolver)
+    : resolver_(resolver) {}
+
+WebRTCStatsReportCallbackResolver::~WebRTCStatsReportCallbackResolver() {
+  DCHECK(
+      ExecutionContext::From(resolver_->GetScriptState())->IsContextThread());
+}
+
+void WebRTCStatsReportCallbackResolver::OnStatsDelivered(
+    std::unique_ptr<WebRTCStatsReport> report) {
+  DCHECK(
+      ExecutionContext::From(resolver_->GetScriptState())->IsContextThread());
+  resolver_->Resolve(new RTCStatsReport(std::move(report)));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.h b/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.h
new file mode 100644
index 0000000..4be485d
--- /dev/null
+++ b/third_party/WebKit/Source/modules/peerconnection/WebRTCStatsReportCallbackResolver.h
@@ -0,0 +1,33 @@
+// 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 WebRTCStatsReportCallbackResolver_h
+#define WebRTCStatsReportCallbackResolver_h
+
+#include <memory>
+
+#include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "modules/peerconnection/RTCStatsReport.h"
+#include "public/platform/WebRTCStats.h"
+
+namespace blink {
+
+class WebRTCStatsReportCallbackResolver : public WebRTCStatsReportCallback {
+ public:
+  // Takes ownership of |resolver|.
+  static std::unique_ptr<WebRTCStatsReportCallback> Create(
+      ScriptPromiseResolver*);
+  ~WebRTCStatsReportCallbackResolver() override;
+
+ private:
+  explicit WebRTCStatsReportCallbackResolver(ScriptPromiseResolver*);
+
+  void OnStatsDelivered(std::unique_ptr<WebRTCStatsReport>) override;
+
+  Persistent<ScriptPromiseResolver> resolver_;
+};
+
+}  // namespace blink
+
+#endif  // WebRTCStatsReportCallbackResolver_h
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
index 4f241891..f973f35 100644
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
@@ -41,8 +41,6 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/loader/BaseFetchContext.h"
-#include "core/loader/DocumentLoader.h"
-#include "core/loader/FrameLoader.h"
 #include "core/loader/MixedContentChecker.h"
 #include "core/loader/SubresourceFilter.h"
 #include "core/loader/ThreadableLoadingContext.h"
@@ -208,27 +206,24 @@
   if (!handle_)
     return false;
 
-  if (GetDocument()) {
-    if (GetDocument()->GetFrame()) {
-      if (MixedContentChecker::ShouldBlockWebSocket(GetDocument()->GetFrame(),
-                                                    url))
-        return false;
+  if (GetDocument() && GetDocument()->GetFrame()) {
+    if (MixedContentChecker::ShouldBlockWebSocket(GetDocument()->GetFrame(),
+                                                  url)) {
+      return false;
     }
-    if (MixedContentChecker::IsMixedContent(GetDocument()->GetSecurityOrigin(),
-                                            url)) {
-      String message =
-          "Connecting to a non-secure WebSocket server from a secure origin is "
-          "deprecated.";
-      GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
-          kJSMessageSource, kWarningMessageLevel, message));
-    }
+    connection_handle_for_scheduler_ = GetDocument()
+                                           ->GetFrame()
+                                           ->GetFrameScheduler()
+                                           ->OnActiveConnectionCreated();
+  }
 
-    if (GetDocument()->GetFrame()) {
-      connection_handle_for_scheduler_ = GetDocument()
-                                             ->GetFrame()
-                                             ->GetFrameScheduler()
-                                             ->OnActiveConnectionCreated();
-    }
+  if (MixedContentChecker::IsMixedContent(
+          GetExecutionContext()->GetSecurityOrigin(), url)) {
+    String message =
+        "Connecting to a non-secure WebSocket server from a secure origin is "
+        "deprecated.";
+    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
+        kJSMessageSource, kWarningMessageLevel, message));
   }
 
   url_ = url;
@@ -245,7 +240,7 @@
   // failure blocks the worker thread which should be avoided. Note that
   // returning "true" just indicates that this was not a mixed content error.
   if (ShouldDisallowConnection(url)) {
-    GetDocument()
+    GetExecutionContext()
         ->GetTaskRunner(TaskType::kNetworking)
         ->PostTask(
             FROM_HERE,
@@ -387,13 +382,12 @@
                                     MessageLevel level,
                                     std::unique_ptr<SourceLocation> location) {
   NETWORK_DVLOG(1) << this << " Fail(" << reason << ")";
-  if (GetDocument()) {
+  if (GetDocument())
     probe::didReceiveWebSocketFrameError(GetDocument(), identifier_, reason);
-    const String message = "WebSocket connection to '" + url_.ElidedString() +
-                           "' failed: " + reason;
-    GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
-        kJSMessageSource, level, message, std::move(location)));
-  }
+  const String message =
+      "WebSocket connection to '" + url_.ElidedString() + "' failed: " + reason;
+  GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
+      kJSMessageSource, level, message, std::move(location)));
   // |reason| is only for logging and should not be provided for scripts,
   // hence close reason must be empty in tearDownFailedConnection.
   TearDownFailedConnection();
@@ -560,12 +554,16 @@
 }
 
 Document* DocumentWebSocketChannel::GetDocument() {
-  ExecutionContext* context = loading_context_->GetExecutionContext();
+  ExecutionContext* context = GetExecutionContext();
   if (context->IsDocument())
     return ToDocument(context);
   return nullptr;
 }
 
+ExecutionContext* DocumentWebSocketChannel::GetExecutionContext() {
+  return loading_context_->GetExecutionContext();
+}
+
 void DocumentWebSocketChannel::DidConnect(WebSocketHandle* handle,
                                           const String& selected_protocol,
                                           const String& extensions) {
@@ -821,10 +819,8 @@
 
 bool DocumentWebSocketChannel::ShouldDisallowConnection(const KURL& url) {
   DCHECK(handle_);
-  DocumentLoader* loader = GetDocument()->Loader();
-  if (!loader)
-    return false;
-  SubresourceFilter* subresource_filter = loader->GetSubresourceFilter();
+  BaseFetchContext* fetch_context = loading_context_->GetFetchContext();
+  SubresourceFilter* subresource_filter = fetch_context->GetSubresourceFilter();
   if (!subresource_filter)
     return false;
   return !subresource_filter->AllowWebSocketConnection(url);
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
index 6a7e1c7f9..1c4a8201 100644
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
@@ -155,8 +155,9 @@
                       const String& reason);
 
   // This may return nullptr.
-  // TODO(kinuko): Remove dependency to document.
+  // TODO(nhiroki): Remove dependency to document (https://crbug.com/825740).
   Document* GetDocument();
+  ExecutionContext* GetExecutionContext();
 
   // WebSocketHandleClient functions.
   void DidConnect(WebSocketHandle*,
diff --git a/third_party/WebKit/Source/platform/blob/BlobBytesProvider.cpp b/third_party/WebKit/Source/platform/blob/BlobBytesProvider.cpp
index 954f61b..af657c18 100644
--- a/third_party/WebKit/Source/platform/blob/BlobBytesProvider.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobBytesProvider.cpp
@@ -152,11 +152,11 @@
 }
 
 void BlobBytesProvider::AppendData(base::span<const char> data) {
-  if (data_.IsEmpty() || data_.back()->length() + data.length() >
-                             kMaxConsolidatedItemSizeInBytes) {
+  if (data_.IsEmpty() ||
+      data_.back()->length() + data.size() > kMaxConsolidatedItemSizeInBytes) {
     AppendData(RawData::Create());
   }
-  data_.back()->MutableData()->Append(data.data(), data.length());
+  data_.back()->MutableData()->Append(data.data(), data.size());
 }
 
 void BlobBytesProvider::RequestAsReply(RequestAsReplyCallback callback) {
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.cpp b/third_party/WebKit/Source/platform/blob/BlobData.cpp
index 6b828eba..8d513e8 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobData.cpp
@@ -268,18 +268,18 @@
   DCHECK_EQ(file_composition_, FileCompositionStatus::NO_UNKNOWN_SIZE_FILES)
       << "Blobs with a unknown-size file cannot have other items.";
   // Skip zero-byte items, as they don't matter for the contents of the blob.
-  if (data.length() == 0)
+  if (data.size() == 0)
     return;
-  bool should_embed_bytes = current_memory_population_ + data.length() <=
+  bool should_embed_bytes = current_memory_population_ + data.size() <=
                             DataElementBytes::kMaximumEmbeddedDataSize;
   if (!elements_.IsEmpty() && elements_.back()->is_bytes()) {
     // Append bytes to previous element.
     DCHECK(last_bytes_provider_);
     const auto& bytes_element = elements_.back()->get_bytes();
-    bytes_element->length += data.length();
+    bytes_element->length += data.size();
     if (should_embed_bytes && bytes_element->embedded_data) {
-      bytes_element->embedded_data->Append(data.data(), data.length());
-      current_memory_population_ += data.length();
+      bytes_element->embedded_data->Append(data.data(), data.size());
+      current_memory_population_ += data.size();
     } else if (bytes_element->embedded_data) {
       current_memory_population_ -= bytes_element->embedded_data->size();
       bytes_element->embedded_data = WTF::nullopt;
@@ -289,12 +289,12 @@
     last_bytes_provider_ =
         BlobBytesProvider::CreateAndBind(MakeRequest(&bytes_provider_info));
 
-    auto bytes_element = DataElementBytes::New(data.length(), WTF::nullopt,
+    auto bytes_element = DataElementBytes::New(data.size(), WTF::nullopt,
                                                std::move(bytes_provider_info));
     if (should_embed_bytes) {
       bytes_element->embedded_data = Vector<uint8_t>();
-      bytes_element->embedded_data->Append(data.data(), data.length());
-      current_memory_population_ += data.length();
+      bytes_element->embedded_data->Append(data.data(), data.size());
+      current_memory_population_ += data.size();
     }
     elements_.push_back(DataElement::NewBytes(std::move(bytes_element)));
   }
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp b/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
index 861d8a1..185c00c 100644
--- a/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
@@ -156,9 +156,12 @@
       base::WrapUnique(extra_data)));
 }
 
-void WebMediaStreamSource::SetEchoCancellation(bool echo_cancellation) {
+void WebMediaStreamSource::SetAudioProcessingProperties(bool echo_cancellation,
+                                                        bool auto_gain_control,
+                                                        bool noise_supression) {
   DCHECK(!private_.IsNull());
-  private_->SetEchoCancellation(echo_cancellation);
+  private_->SetAudioProcessingProperties(echo_cancellation, auto_gain_control,
+                                         noise_supression);
 }
 
 WebMediaConstraints WebMediaStreamSource::Constraints() {
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
index 4dbb250..70885b2 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
@@ -7,6 +7,7 @@
 #include <memory>
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/trace_event/trace_event.h"
 #include "cc/resources/layer_tree_resource_provider.h"
 #include "cc/resources/video_resource_updater.h"
 #include "components/viz/common/gpu/context_provider.h"
@@ -68,6 +69,7 @@
     viz::RenderPass* render_pass,
     scoped_refptr<media::VideoFrame> frame,
     media::VideoRotation rotation) {
+  TRACE_EVENT0("media", "VideoFrameResourceProvider::AppendQuads");
   gfx::Transform transform = gfx::Transform();
   gfx::Size rotated_size = frame->coded_size();
 
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
index 689f857..81e2091 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
@@ -5,6 +5,7 @@
 #include "platform/graphics/VideoFrameSubmitter.h"
 
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
 #include "cc/paint/filter_operations.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/resources/video_resource_updater.h"
@@ -116,6 +117,7 @@
 void VideoFrameSubmitter::SubmitFrame(
     viz::BeginFrameAck begin_frame_ack,
     scoped_refptr<media::VideoFrame> video_frame) {
+  TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame");
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
   DCHECK(compositor_frame_sink_);
 
@@ -152,6 +154,7 @@
 }
 
 void VideoFrameSubmitter::OnBeginFrame(const viz::BeginFrameArgs& args) {
+  TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame");
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
   viz::BeginFrameAck current_begin_frame_ack =
       viz::BeginFrameAck(args.source_id, args.sequence_number, false);
diff --git a/third_party/WebKit/Source/platform/heap/BUILD.gn b/third_party/WebKit/Source/platform/heap/BUILD.gn
index 8e52bc0d..68731a7 100644
--- a/third_party/WebKit/Source/platform/heap/BUILD.gn
+++ b/third_party/WebKit/Source/platform/heap/BUILD.gn
@@ -30,8 +30,6 @@
     "BlinkGC.h",
     "BlinkGCMemoryDumpProvider.cpp",
     "BlinkGCMemoryDumpProvider.h",
-    "CallbackStack.cpp",
-    "CallbackStack.h",
     "GCInfo.cpp",
     "GCInfo.h",
     "GCTaskRunner.h",
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp b/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
deleted file mode 100644
index 074204c..0000000
--- a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "platform/heap/CallbackStack.h"
-
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "platform/wtf/StdLibExtras.h"
-#include "platform/wtf/allocator/Partitions.h"
-
-namespace blink {
-
-CallbackStackMemoryPool& CallbackStackMemoryPool::Instance() {
-  DEFINE_STATIC_LOCAL(CallbackStackMemoryPool, memory_pool, ());
-  return memory_pool;
-}
-
-void CallbackStackMemoryPool::Initialize() {
-  free_list_first_ = 0;
-  for (size_t index = 0; index < kPooledBlockCount - 1; ++index) {
-    free_list_next_[index] = index + 1;
-  }
-  free_list_next_[kPooledBlockCount - 1] = -1;
-  pooled_memory_ = static_cast<CallbackStack::Item*>(
-      WTF::AllocPages(nullptr, kBlockBytes * kPooledBlockCount,
-                      WTF::kPageAllocationGranularity, WTF::PageReadWrite));
-  CHECK(pooled_memory_);
-}
-
-CallbackStack::Item* CallbackStackMemoryPool::Allocate() {
-  MutexLocker locker(mutex_);
-  // Allocate from a free list if available.
-  if (free_list_first_ != -1) {
-    size_t index = free_list_first_;
-    DCHECK(0 <= index && index < CallbackStackMemoryPool::kPooledBlockCount);
-    free_list_first_ = free_list_next_[index];
-    free_list_next_[index] = -1;
-    return pooled_memory_ + kBlockSize * index;
-  }
-  // Otherwise, allocate a new memory region.
-  CallbackStack::Item* memory =
-      static_cast<CallbackStack::Item*>(WTF::Partitions::FastZeroedMalloc(
-          kBlockBytes, "CallbackStackMemoryPool"));
-  CHECK(memory);
-  return memory;
-}
-
-void CallbackStackMemoryPool::Free(CallbackStack::Item* memory) {
-  MutexLocker locker(mutex_);
-  int index = (reinterpret_cast<uintptr_t>(memory) -
-               reinterpret_cast<uintptr_t>(pooled_memory_)) /
-              (kBlockSize * sizeof(CallbackStack::Item));
-  // If the memory is a newly allocated region, free the memory.
-  if (index < 0 || static_cast<int>(kPooledBlockCount) <= index) {
-    WTF::Partitions::FastFree(memory);
-    return;
-  }
-  // Otherwise, return the memory back to the free list.
-  DCHECK_EQ(free_list_next_[index], -1);
-  free_list_next_[index] = free_list_first_;
-  free_list_first_ = index;
-}
-
-CallbackStack::Block::Block(Block* next) {
-  buffer_ = CallbackStackMemoryPool::Instance().Allocate();
-#if DCHECK_IS_ON()
-  Clear();
-#endif
-
-  limit_ = &(buffer_[CallbackStackMemoryPool::kBlockSize]);
-  current_ = &(buffer_[0]);
-  next_ = next;
-}
-
-CallbackStack::Block::~Block() {
-  CallbackStackMemoryPool::Instance().Free(buffer_);
-  buffer_ = nullptr;
-  limit_ = nullptr;
-  current_ = nullptr;
-  next_ = nullptr;
-}
-
-#if DCHECK_IS_ON()
-void CallbackStack::Block::Clear() {
-  for (size_t i = 0; i < CallbackStackMemoryPool::kBlockSize; i++)
-    buffer_[i] = Item(nullptr, nullptr);
-}
-#endif
-
-void CallbackStack::Block::InvokeEphemeronCallbacks(Visitor* visitor) {
-  // This loop can tolerate entries being added by the callbacks after
-  // iteration starts.
-  for (unsigned i = 0; buffer_ + i < current_; i++) {
-    Item& item = buffer_[i];
-    item.Call(visitor);
-  }
-}
-
-#if DCHECK_IS_ON()
-bool CallbackStack::Block::HasCallbackForObject(const void* object) {
-  for (unsigned i = 0; buffer_ + i < current_; i++) {
-    Item* item = &buffer_[i];
-    if (item->Object() == object)
-      return true;
-  }
-  return false;
-}
-#endif
-
-std::unique_ptr<CallbackStack> CallbackStack::Create() {
-  return base::WrapUnique(new CallbackStack());
-}
-
-CallbackStack::CallbackStack() : first_(nullptr), last_(nullptr) {}
-
-CallbackStack::~CallbackStack() {
-  CHECK(IsEmpty());
-  first_ = nullptr;
-  last_ = nullptr;
-}
-
-void CallbackStack::Commit() {
-  DCHECK(!first_);
-  first_ = new Block(first_);
-  last_ = first_;
-}
-
-void CallbackStack::Decommit() {
-  if (!first_)
-    return;
-  Block* next;
-  for (Block* current = first_->Next(); current; current = next) {
-    next = current->Next();
-    delete current;
-  }
-  delete first_;
-  last_ = first_ = nullptr;
-}
-
-bool CallbackStack::IsEmpty() const {
-  return !first_ || (HasJustOneBlock() && first_->IsEmptyBlock());
-}
-
-CallbackStack::Item* CallbackStack::AllocateEntrySlow() {
-  DCHECK(first_);
-  DCHECK(!first_->AllocateEntry());
-  first_ = new Block(first_);
-  return first_->AllocateEntry();
-}
-
-CallbackStack::Item* CallbackStack::PopSlow() {
-  DCHECK(first_);
-  DCHECK(first_->IsEmptyBlock());
-
-  for (;;) {
-    Block* next = first_->Next();
-    if (!next) {
-#if DCHECK_IS_ON()
-      first_->Clear();
-#endif
-      return nullptr;
-    }
-    delete first_;
-    first_ = next;
-    if (Item* item = first_->Pop())
-      return item;
-  }
-}
-
-void CallbackStack::InvokeEphemeronCallbacks(Visitor* visitor) {
-  // The first block is the only one where new ephemerons are added, so we
-  // call the callbacks on that last, to catch any new ephemerons discovered
-  // in the callbacks.
-  // However, if enough ephemerons were added, we may have a new block that
-  // has been prepended to the chain. This will be very rare, but we can
-  // handle the situation by starting again and calling all the callbacks
-  // on the prepended blocks.
-  Block* from = nullptr;
-  Block* upto = nullptr;
-  while (from != first_) {
-    upto = from;
-    from = first_;
-    InvokeOldestCallbacks(from, upto, visitor);
-  }
-}
-
-void CallbackStack::InvokeOldestCallbacks(Block* from,
-                                          Block* upto,
-                                          Visitor* visitor) {
-  if (from == upto)
-    return;
-  DCHECK(from);
-  // Recurse first so we get to the newly added entries last.
-  InvokeOldestCallbacks(from->Next(), upto, visitor);
-  from->InvokeEphemeronCallbacks(visitor);
-}
-
-bool CallbackStack::HasJustOneBlock() const {
-  DCHECK(first_);
-  return !first_->Next();
-}
-
-#if DCHECK_IS_ON()
-bool CallbackStack::HasCallbackForObject(const void* object) {
-  for (Block* current = first_; current; current = current->Next()) {
-    if (current->HasCallbackForObject(object))
-      return true;
-  }
-  return false;
-}
-#endif
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.h b/third_party/WebKit/Source/platform/heap/CallbackStack.h
deleted file mode 100644
index 94c0eab..0000000
--- a/third_party/WebKit/Source/platform/heap/CallbackStack.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CallbackStack_h
-#define CallbackStack_h
-
-#include "platform/heap/BlinkGC.h"
-#include "platform/wtf/Allocator.h"
-#include "platform/wtf/Assertions.h"
-#include "platform/wtf/Threading.h"
-#include "platform/wtf/ThreadingPrimitives.h"
-
-namespace blink {
-
-// The CallbackStack contains all the visitor callbacks used to trace and mark
-// objects. A specific CallbackStack instance contains at most bufferSize
-// elements.
-// If more space is needed a new CallbackStack instance is created and chained
-// together with the former instance. I.e. a logical CallbackStack can be made
-// of multiple chained CallbackStack object instances.
-class PLATFORM_EXPORT CallbackStack final {
-  USING_FAST_MALLOC(CallbackStack);
-
- public:
-  class Item {
-    DISALLOW_NEW();
-
-   public:
-    Item() = default;
-    Item(void* object, VisitorCallback callback)
-        : object_(object), callback_(callback) {}
-    void* Object() { return object_; }
-    VisitorCallback Callback() { return callback_; }
-    void Call(Visitor* visitor) { callback_(visitor, object_); }
-
-   private:
-    void* object_;
-    VisitorCallback callback_;
-  };
-
-  static std::unique_ptr<CallbackStack> Create();
-  ~CallbackStack();
-
-  void Commit();
-  void Decommit();
-
-  Item* AllocateEntry();
-  Item* Pop();
-
-  bool IsEmpty() const;
-
-  void InvokeEphemeronCallbacks(Visitor*);
-
-#if DCHECK_IS_ON()
-  bool HasCallbackForObject(const void*);
-#endif
-  bool HasJustOneBlock() const;
-
-  static const size_t kMinimalBlockSize;
-  static const size_t kDefaultBlockSize = (1 << 13);
-
- private:
-  class Block {
-    USING_FAST_MALLOC(Block);
-
-   public:
-    explicit Block(Block* next);
-    ~Block();
-
-#if DCHECK_IS_ON()
-    void Clear();
-#endif
-    Block* Next() const { return next_; }
-    void SetNext(Block* next) { next_ = next; }
-
-    bool IsEmptyBlock() const { return current_ == &(buffer_[0]); }
-
-    size_t BlockSize() const { return block_size_; }
-
-    Item* AllocateEntry() {
-      if (LIKELY(current_ < limit_))
-        return current_++;
-      return nullptr;
-    }
-
-    Item* Pop() {
-      if (UNLIKELY(IsEmptyBlock()))
-        return nullptr;
-      return --current_;
-    }
-
-    void InvokeEphemeronCallbacks(Visitor*);
-
-#if DCHECK_IS_ON()
-    bool HasCallbackForObject(const void*);
-#endif
-
-   private:
-    size_t block_size_;
-
-    Item* buffer_;
-    Item* limit_;
-    Item* current_;
-    Block* next_;
-  };
-
-  CallbackStack();
-  Item* PopSlow();
-  Item* AllocateEntrySlow();
-  void InvokeOldestCallbacks(Block*, Block*, Visitor*);
-
-  Block* first_;
-  Block* last_;
-};
-
-class CallbackStackMemoryPool final {
-  USING_FAST_MALLOC(CallbackStackMemoryPool);
-
- public:
-  // 2048 * 8 * sizeof(Item) = 256 KB (64bit) is pre-allocated for the
-  // underlying buffer of CallbackStacks.
-  static const size_t kBlockSize = 2048;
-  static const size_t kPooledBlockCount = 8;
-  static const size_t kBlockBytes = kBlockSize * sizeof(CallbackStack::Item);
-
-  static CallbackStackMemoryPool& Instance();
-
-  void Initialize();
-  CallbackStack::Item* Allocate();
-  void Free(CallbackStack::Item*);
-
- private:
-  Mutex mutex_;
-  int free_list_first_;
-  int free_list_next_[kPooledBlockCount];
-  CallbackStack::Item* pooled_memory_;
-};
-
-ALWAYS_INLINE CallbackStack::Item* CallbackStack::AllocateEntry() {
-  DCHECK(first_);
-  Item* item = first_->AllocateEntry();
-  if (LIKELY(!!item))
-    return item;
-
-  return AllocateEntrySlow();
-}
-
-ALWAYS_INLINE CallbackStack::Item* CallbackStack::Pop() {
-  Item* item = first_->Pop();
-  if (LIKELY(!!item))
-    return item;
-
-  return PopSlow();
-}
-
-}  // namespace blink
-
-#endif  // CallbackStack_h
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index f9db2c19..0ebf038 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -38,7 +38,6 @@
 #include "platform/Histogram.h"
 #include "platform/bindings/ScriptForbiddenScope.h"
 #include "platform/heap/BlinkGCMemoryDumpProvider.h"
-#include "platform/heap/CallbackStack.h"
 #include "platform/heap/HeapCompact.h"
 #include "platform/heap/MarkingVisitor.h"
 #include "platform/heap/PageMemory.h"
@@ -163,7 +162,7 @@
 
 Address ThreadHeap::CheckAndMarkPointer(MarkingVisitor* visitor,
                                         Address address) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
 
 #if !DCHECK_IS_ON()
   if (heap_does_not_contain_cache_->Lookup(address))
@@ -197,7 +196,7 @@
     MarkingVisitor* visitor,
     Address address,
     MarkedPointerCallbackForTesting callback) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
 
   if (BasePage* page = LookupPageForAddress(address)) {
     DCHECK(page->Contains(address));
@@ -214,7 +213,7 @@
 
 void ThreadHeap::RegisterWeakTable(void* table,
                                    EphemeronCallback iteration_callback) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
 #if DCHECK_IS_ON()
   auto result = ephemeron_callbacks_.insert(table, iteration_callback);
   DCHECK(result.is_new_entry ||
@@ -452,18 +451,16 @@
 }
 
 size_t ThreadHeap::ObjectPayloadSizeForTesting() {
+  ThreadState::AtomicPauseScope atomic_pause_scope(thread_state_);
   size_t object_payload_size = 0;
   thread_state_->SetGCPhase(ThreadState::GCPhase::kMarking);
-  thread_state_->SetGCState(ThreadState::kGCRunning);
   thread_state_->Heap().MakeConsistentForGC();
   thread_state_->Heap().PrepareForSweep();
   for (int i = 0; i < BlinkGC::kNumberOfArenas; ++i)
     object_payload_size += arenas_[i]->ObjectPayloadSizeForTesting();
   MakeConsistentForMutator();
   thread_state_->SetGCPhase(ThreadState::GCPhase::kSweeping);
-  thread_state_->SetGCState(ThreadState::kSweeping);
   thread_state_->SetGCPhase(ThreadState::GCPhase::kNone);
-  thread_state_->SetGCState(ThreadState::kNoGCScheduled);
   return object_payload_size;
 }
 
@@ -488,19 +485,19 @@
 }
 
 void ThreadHeap::VisitPersistentRoots(Visitor* visitor) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   TRACE_EVENT0("blink_gc", "ThreadHeap::visitPersistentRoots");
   thread_state_->VisitPersistents(visitor);
 }
 
 void ThreadHeap::VisitStackRoots(MarkingVisitor* visitor) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   TRACE_EVENT0("blink_gc", "ThreadHeap::visitStackRoots");
   thread_state_->VisitStack(visitor);
 }
 
 BasePage* ThreadHeap::LookupPageForAddress(Address address) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   if (PageMemoryRegion* region = region_tree_->Lookup(address)) {
     return region->PageFromAddress(address);
   }
@@ -508,7 +505,7 @@
 }
 
 void ThreadHeap::ResetHeapCounters() {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
 
   ThreadHeap::ReportMemoryUsageForTracing();
 
@@ -519,14 +516,14 @@
 }
 
 void ThreadHeap::MakeConsistentForGC() {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   TRACE_EVENT0("blink_gc", "ThreadHeap::MakeConsistentForGC");
   for (int i = 0; i < BlinkGC::kNumberOfArenas; ++i)
     arenas_[i]->MakeConsistentForGC();
 }
 
 void ThreadHeap::MakeConsistentForMutator() {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   for (int i = 0; i < BlinkGC::kNumberOfArenas; ++i)
     arenas_[i]->MakeConsistentForMutator();
 }
@@ -556,7 +553,7 @@
 }
 
 void ThreadHeap::PrepareForSweep() {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
   DCHECK(thread_state_->CheckThread());
   for (int i = 0; i < BlinkGC::kNumberOfArenas; i++)
     arenas_[i]->PrepareForSweep();
@@ -660,7 +657,7 @@
 #endif
 
 void ThreadHeap::TakeSnapshot(SnapshotType type) {
-  DCHECK(thread_state_->IsInGC());
+  DCHECK(thread_state_->InAtomicMarkingPause());
 
   // 0 is used as index for freelist entries. Objects are indexed 1 to
   // gcInfoIndex.
diff --git a/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp b/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
index 595f2dc..88fc31b 100644
--- a/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapAllocator.cpp
@@ -13,7 +13,7 @@
   ThreadState* state = ThreadState::Current();
   if (state->SweepForbidden())
     return;
-  DCHECK(!state->IsInGC());
+  DCHECK(!state->in_atomic_pause());
 
   // Don't promptly free large objects because their page is never reused.
   // Don't free backings allocated on other threads.
@@ -41,8 +41,7 @@
 }
 
 void HeapAllocator::FreeHashTableBacking(void* address, bool is_weak_table) {
-  if (!ThreadState::Current()->IsIncrementalMarkingInProgress() ||
-      !is_weak_table)
+  if (!ThreadState::Current()->IsMarkingInProgress() || !is_weak_table)
     BackingFree(address);
 }
 
@@ -53,7 +52,7 @@
   ThreadState* state = ThreadState::Current();
   if (state->SweepForbidden())
     return false;
-  DCHECK(!state->IsInGC());
+  DCHECK(!state->in_atomic_pause());
   DCHECK(state->IsAllocationAllowed());
   DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
 
@@ -94,7 +93,7 @@
   ThreadState* state = ThreadState::Current();
   if (state->SweepForbidden())
     return false;
-  DCHECK(!state->IsInGC());
+  DCHECK(!state->in_atomic_pause());
   DCHECK(state->IsAllocationAllowed());
   DCHECK_EQ(&state->Heap(), &ThreadState::FromObject(address)->Heap());
 
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index 27b5aaa..6e15e37 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -35,7 +35,6 @@
 #include "platform/MemoryCoordinator.h"
 #include "platform/bindings/ScriptForbiddenScope.h"
 #include "platform/heap/BlinkGCMemoryDumpProvider.h"
-#include "platform/heap/CallbackStack.h"
 #include "platform/heap/HeapCompact.h"
 #include "platform/heap/MarkingVerifier.h"
 #include "platform/heap/PageMemory.h"
@@ -227,7 +226,7 @@
 }
 
 void BaseArena::PrepareForSweep() {
-  DCHECK(GetThreadState()->IsInGC());
+  DCHECK(GetThreadState()->InAtomicMarkingPause());
   DCHECK(SweepingCompleted());
 
   ClearFreeLists();
@@ -1792,7 +1791,7 @@
 }
 
 bool HeapDoesNotContainCache::Lookup(Address address) {
-  DCHECK(ThreadState::Current()->IsInGC());
+  DCHECK(ThreadState::Current()->InAtomicMarkingPause());
 
   size_t index = GetHash(address);
   DCHECK(!(index & 1));
@@ -1805,7 +1804,7 @@
 }
 
 void HeapDoesNotContainCache::AddEntry(Address address) {
-  DCHECK(ThreadState::Current()->IsInGC());
+  DCHECK(ThreadState::Current()->InAtomicMarkingPause());
 
   has_entries_ = true;
   size_t index = GetHash(address);
diff --git a/third_party/WebKit/Source/platform/heap/IncrementalMarkingTest.cpp b/third_party/WebKit/Source/platform/heap/IncrementalMarkingTest.cpp
index 2d05032..4cb0c498 100644
--- a/third_party/WebKit/Source/platform/heap/IncrementalMarkingTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/IncrementalMarkingTest.cpp
@@ -5,7 +5,6 @@
 #include <initializer_list>
 #include <vector>
 
-#include "platform/heap/CallbackStack.h"
 #include "platform/heap/GarbageCollected.h"
 #include "platform/heap/Heap.h"
 #include "platform/heap/HeapAllocator.h"
diff --git a/third_party/WebKit/Source/platform/heap/MarkingVisitor.h b/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
index 85c71a7..569ad56 100644
--- a/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
+++ b/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
@@ -147,7 +147,7 @@
 
 inline bool MarkingVisitor::MarkHeaderNoTracing(HeapObjectHeader* header) {
   DCHECK(header);
-  DCHECK(State()->IsInGC() || State()->IsIncrementalMarking());
+  DCHECK(State()->InAtomicMarkingPause() || State()->IsIncrementalMarking());
   // A GC should only mark the objects that belong in its heap.
   DCHECK_EQ(State(),
             PageFromObject(header->Payload())->Arena()->GetThreadState());
diff --git a/third_party/WebKit/Source/platform/heap/ProcessHeap.cpp b/third_party/WebKit/Source/platform/heap/ProcessHeap.cpp
index bc096a5..869aa46 100644
--- a/third_party/WebKit/Source/platform/heap/ProcessHeap.cpp
+++ b/third_party/WebKit/Source/platform/heap/ProcessHeap.cpp
@@ -5,7 +5,6 @@
 #include "platform/heap/ProcessHeap.h"
 
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
-#include "platform/heap/CallbackStack.h"
 #include "platform/heap/GCInfo.h"
 #include "platform/heap/Heap.h"
 #include "platform/heap/PersistentNode.h"
@@ -31,7 +30,6 @@
   total_marked_object_size_ = 0;
 
   GCInfoTable::Init();
-  CallbackStackMemoryPool::Instance().Initialize();
 
   base::SamplingHeapProfiler::SetHooksInstallCallback([]() {
     HeapAllocHooks::SetAllocationHook(&BlinkGCAllocHook);
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index c3a2470..e19eb1e 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -43,7 +43,6 @@
 #include "platform/Histogram.h"
 #include "platform/bindings/RuntimeCallStats.h"
 #include "platform/heap/BlinkGCMemoryDumpProvider.h"
-#include "platform/heap/CallbackStack.h"
 #include "platform/heap/Handle.h"
 #include "platform/heap/Heap.h"
 #include "platform/heap/HeapCompact.h"
@@ -419,7 +418,7 @@
 #if BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING)
   // TODO(mlippautz): For now immediately schedule incremental marking if
   // the runtime flag is provided, basically exercising a stress test.
-  return (GcState() == kNoGCScheduled || GcState() == kSweeping) &&
+  return GcState() == kNoGCScheduled &&
          RuntimeEnabledFeatures::HeapIncrementalMarkingEnabled();
 #else
   return false;
@@ -686,18 +685,19 @@
 }
 
 void ThreadState::ScheduleIdleGC() {
-  if (IsSweepingInProgress()) {
-    SetGCState(kSweepingAndIdleGCScheduled);
+  SetGCState(kIdleGCScheduled);
+  if (IsSweepingInProgress())
+    return;
+  // Some threads (e.g. PPAPI thread) don't have a scheduler.
+  // Also some tests can call Platform::SetCurrentPlatformForTesting() at any
+  // time, so we need to check for the scheduler here instead of
+  // ScheduleIdleGC().
+  if (!Platform::Current()->CurrentThread()->Scheduler()) {
+    SetGCState(kNoGCScheduled);
     return;
   }
-
-  // Some threads (e.g. PPAPI thread) don't have a scheduler.
-  if (!Platform::Current()->CurrentThread()->Scheduler())
-    return;
-
   Platform::Current()->CurrentThread()->Scheduler()->PostNonNestableIdleTask(
       FROM_HERE, WTF::Bind(&ThreadState::PerformIdleGC, WTF::Unretained(this)));
-  SetGCState(kIdleGCScheduled);
 }
 
 void ThreadState::ScheduleIdleLazySweep() {
@@ -712,11 +712,6 @@
 
 void ThreadState::SchedulePreciseGC() {
   DCHECK(CheckThread());
-  if (IsSweepingInProgress()) {
-    SetGCState(kSweepingAndPreciseGCScheduled);
-    return;
-  }
-
   SetGCState(kPreciseGCScheduled);
 }
 
@@ -733,10 +728,6 @@
     UNEXPECTED_GCSTATE(kIdleGCScheduled);
     UNEXPECTED_GCSTATE(kPreciseGCScheduled);
     UNEXPECTED_GCSTATE(kFullGCScheduled);
-    UNEXPECTED_GCSTATE(kGCRunning);
-    UNEXPECTED_GCSTATE(kSweeping);
-    UNEXPECTED_GCSTATE(kSweepingAndIdleGCScheduled);
-    UNEXPECTED_GCSTATE(kSweepingAndPreciseGCScheduled);
     UNEXPECTED_GCSTATE(kIncrementalMarkingStartScheduled);
     UNEXPECTED_GCSTATE(kIncrementalMarkingStepScheduled);
     UNEXPECTED_GCSTATE(kIncrementalMarkingFinalizeScheduled);
@@ -757,13 +748,14 @@
     case kNoGCScheduled:
       DCHECK(CheckThread());
       VERIFY_STATE_TRANSITION(
-          gc_state_ == kSweeping || gc_state_ == kSweepingAndIdleGCScheduled ||
+          gc_state_ == kNoGCScheduled || gc_state_ == kIdleGCScheduled ||
+          gc_state_ == kPreciseGCScheduled || gc_state_ == kFullGCScheduled ||
+          gc_state_ == kPageNavigationGCScheduled ||
           gc_state_ == kIncrementalMarkingFinalizeScheduled);
       break;
     case kIncrementalMarkingStartScheduled:
       DCHECK(CheckThread());
-      VERIFY_STATE_TRANSITION((gc_state_ == kSweeping) ||
-                              (gc_state_ == kNoGCScheduled));
+      VERIFY_STATE_TRANSITION(gc_state_ == kNoGCScheduled);
       break;
     case kIncrementalMarkingStepScheduled:
       DCHECK(CheckThread());
@@ -774,35 +766,20 @@
       DCHECK(CheckThread());
       VERIFY_STATE_TRANSITION(gc_state_ == kIncrementalMarkingStepScheduled);
       break;
-    case kIdleGCScheduled:
-    case kPreciseGCScheduled:
     case kFullGCScheduled:
     case kPageNavigationGCScheduled:
+      // These GCs should not be scheduled while sweeping is in progress.
+      DCHECK(!IsSweepingInProgress());
+      FALLTHROUGH;
+    case kIdleGCScheduled:
+    case kPreciseGCScheduled:
       DCHECK(CheckThread());
       VERIFY_STATE_TRANSITION(
           gc_state_ == kNoGCScheduled || gc_state_ == kIdleGCScheduled ||
           gc_state_ == kPreciseGCScheduled || gc_state_ == kFullGCScheduled ||
-          gc_state_ == kPageNavigationGCScheduled || gc_state_ == kSweeping ||
-          gc_state_ == kSweepingAndIdleGCScheduled ||
-          gc_state_ == kSweepingAndPreciseGCScheduled);
+          gc_state_ == kPageNavigationGCScheduled);
       CompleteSweep();
       break;
-    case kGCRunning:
-      DCHECK(!IsInGC());
-      VERIFY_STATE_TRANSITION(gc_state_ != kGCRunning);
-      break;
-    case kSweeping:
-      DCHECK(IsInGC());
-      DCHECK(CheckThread());
-      VERIFY_STATE_TRANSITION(gc_state_ == kGCRunning);
-      break;
-    case kSweepingAndIdleGCScheduled:
-    case kSweepingAndPreciseGCScheduled:
-      DCHECK(CheckThread());
-      VERIFY_STATE_TRANSITION(gc_state_ == kSweeping ||
-                              gc_state_ == kSweepingAndIdleGCScheduled ||
-                              gc_state_ == kSweepingAndPreciseGCScheduled);
-      break;
     default:
       NOTREACHED();
   }
@@ -870,7 +847,7 @@
 
 void ThreadState::PreSweep(BlinkGC::MarkingType marking_type,
                            BlinkGC::SweepingType sweeping_type) {
-  DCHECK(IsInGC());
+  DCHECK(InAtomicMarkingPause());
   DCHECK(CheckThread());
   Heap().PrepareForSweep();
 
@@ -893,9 +870,8 @@
     return;
   }
 
-  // We have to set the GCState to Sweeping before calling pre-finalizers
+  // We have to set the GCPhase to Sweeping before calling pre-finalizers
   // to disallow a GC during the pre-finalizers.
-  SetGCState(kSweeping);
   SetGCPhase(GCPhase::kSweeping);
 
   // Allocation is allowed during the pre-finalizers and destructors.
@@ -1041,20 +1017,8 @@
   }
 
   SetGCPhase(GCPhase::kNone);
-  switch (GcState()) {
-    case kSweeping:
-      SetGCState(kNoGCScheduled);
-      break;
-    case kSweepingAndPreciseGCScheduled:
-      SetGCState(kPreciseGCScheduled);
-      break;
-    case kSweepingAndIdleGCScheduled:
-      SetGCState(kNoGCScheduled);
-      ScheduleIdleGC();
-      break;
-    default:
-      NOTREACHED();
-  }
+  if (GcState() == kIdleGCScheduled)
+    ScheduleIdleGC();
 
   gc_age_++;
 
@@ -1302,6 +1266,8 @@
   RUNTIME_CALL_TIMER_SCOPE_IF_ISOLATE_EXISTS(
       GetIsolate(), RuntimeCallStats::CounterId::kCollectGarbage);
 
+  SetGCState(kNoGCScheduled);
+
   {
     AtomicPauseScope atomic_pause_scope(this);
     {
@@ -1385,8 +1351,7 @@
   if (isolate_ && perform_cleanup_)
     perform_cleanup_(isolate_);
 
-  DCHECK(!IsInGC());
-  SetGCState(kGCRunning);
+  DCHECK(InAtomicMarkingPause());
   Heap().MakeConsistentForGC();
   Heap().FlushHeapDoesNotContainCacheIfNeeded();
   Heap().ClearArenaAges();
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 72715002..d6b6b460 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -150,10 +150,6 @@
     kPreciseGCScheduled,
     kFullGCScheduled,
     kPageNavigationGCScheduled,
-    kGCRunning,
-    kSweeping,
-    kSweepingAndIdleGCScheduled,
-    kSweepingAndPreciseGCScheduled,
   };
 
   // The phase that the GC is in. The GCPhase will not return kNone for mutators
@@ -263,17 +259,13 @@
   void SchedulePageNavigationGCIfNeeded(float estimated_removal_ratio);
   void SchedulePageNavigationGC();
   void ScheduleGCIfNeeded();
+  void PostIdleGCTask();
   void WillStartV8GC(BlinkGC::V8GCType);
   void SetGCState(GCState);
   GCState GcState() const { return gc_state_; }
   void SetGCPhase(GCPhase);
-  bool IsInGC() const { return GcState() == kGCRunning; }
   bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; }
-  bool IsSweepingInProgress() const {
-    return GcState() == kSweeping ||
-           GcState() == kSweepingAndPreciseGCScheduled ||
-           GcState() == kSweepingAndIdleGCScheduled;
-  }
+  bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; }
 
   // Incremental GC.
 
@@ -285,11 +277,6 @@
   void IncrementalMarkingStep();
   void IncrementalMarkingFinalize();
 
-  bool IsIncrementalMarkingInProgress() const {
-    return GcState() == kIncrementalMarkingStepScheduled ||
-           GcState() == kIncrementalMarkingFinalizeScheduled;
-  }
-
   // A GC runs in the following sequence.
   //
   // 1) preGC() is called.
@@ -300,12 +287,6 @@
   // 4) Lazy sweeping sweeps heaps incrementally. completeSweep() may be called
   //    to complete the sweeping.
   // 5) postSweep() is called.
-  //
-  // Notes:
-  // - The world is stopped between 1) and 3).
-  // - isInGC() returns true between 1) and 3).
-  // - isSweepingInProgress() returns true while any sweeping operation is
-  //   running.
   void MarkPhasePrologue(BlinkGC::StackState,
                          BlinkGC::MarkingType,
                          BlinkGC::GCReason);
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
index 29b98fa2..b81a216 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
@@ -90,6 +90,14 @@
   observers_.insert(observer);
 }
 
+void MediaStreamSource::SetAudioProcessingProperties(bool echo_cancellation,
+                                                     bool auto_gain_control,
+                                                     bool noise_supression) {
+  echo_cancellation_ = echo_cancellation;
+  auto_gain_control_ = auto_gain_control;
+  noise_supression_ = noise_supression;
+}
+
 void MediaStreamSource::AddAudioConsumer(AudioDestinationConsumer* consumer) {
   DCHECK(requires_consumer_);
   MutexLocker locker(audio_consumers_lock_);
@@ -110,8 +118,12 @@
 void MediaStreamSource::GetSettings(WebMediaStreamTrack::Settings& settings) {
   settings.device_id = Id();
 
-  if (echo_cancellation_.has_value())
+  if (echo_cancellation_)
     settings.echo_cancellation = *echo_cancellation_;
+  if (auto_gain_control_)
+    settings.auto_gain_control = *auto_gain_control_;
+  if (noise_supression_)
+    settings.noise_supression = *noise_supression_;
 }
 
 void MediaStreamSource::SetAudioFormat(size_t number_of_channels,
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
index f161922..8fa7155 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
@@ -94,9 +94,9 @@
     extra_data_ = std::move(extra_data);
   }
 
-  void SetEchoCancellation(bool echo_cancellation) {
-    echo_cancellation_ = WTF::make_optional(echo_cancellation);
-  }
+  void SetAudioProcessingProperties(bool echo_cancellation,
+                                    bool auto_gain_control,
+                                    bool noise_supression);
 
   void SetConstraints(WebMediaConstraints constraints) {
     constraints_ = constraints;
@@ -147,7 +147,9 @@
   std::unique_ptr<ExtraData> extra_data_;
   WebMediaConstraints constraints_;
   WebMediaStreamSource::Capabilities capabilities_;
-  WTF::Optional<bool> echo_cancellation_;
+  Optional<bool> echo_cancellation_;
+  Optional<bool> auto_gain_control_;
+  Optional<bool> noise_supression_;
 };
 
 typedef HeapVector<Member<MediaStreamSource>> MediaStreamSourceVector;
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index 7d9b1cc..d6c6aed8 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -501,7 +501,7 @@
     {
       name: "FramebustingNeedsSameOriginOrUserGesture",
       settable_from_internals: true,
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "FramesTimingFunction",
diff --git a/third_party/WebKit/public/platform/WebMediaStreamSource.h b/third_party/WebKit/public/platform/WebMediaStreamSource.h
index d588e171..202fbef7 100644
--- a/third_party/WebKit/public/platform/WebMediaStreamSource.h
+++ b/third_party/WebKit/public/platform/WebMediaStreamSource.h
@@ -126,7 +126,10 @@
   BLINK_PLATFORM_EXPORT ExtraData* GetExtraData() const;
   BLINK_PLATFORM_EXPORT void SetExtraData(ExtraData*);
 
-  BLINK_PLATFORM_EXPORT void SetEchoCancellation(bool echo_cancellation);
+  BLINK_PLATFORM_EXPORT void SetAudioProcessingProperties(
+      bool echo_cancellation,
+      bool auto_gain_control,
+      bool noise_supression);
 
   BLINK_PLATFORM_EXPORT WebMediaConstraints Constraints();
 
diff --git a/third_party/WebKit/public/platform/WebMediaStreamTrack.h b/third_party/WebKit/public/platform/WebMediaStreamTrack.h
index d3551ed..a9d4ca6 100644
--- a/third_party/WebKit/public/platform/WebMediaStreamTrack.h
+++ b/third_party/WebKit/public/platform/WebMediaStreamTrack.h
@@ -28,6 +28,7 @@
 #include "WebCommon.h"
 #include "WebPrivatePtr.h"
 #include "WebString.h"
+#include "base/optional.h"
 
 namespace blink {
 
@@ -49,7 +50,6 @@
     bool HasHeight() const { return height >= 0; }
     bool HasAspectRatio() const { return aspect_ratio >= 0.0; }
     bool HasFacingMode() const { return facing_mode != FacingMode::kNone; }
-    bool HasEchoCancellationValue() const { return echo_cancellation >= 0; }
     bool HasVideoKind() const { return !video_kind.IsNull(); }
     bool HasFocalLengthX() const { return focal_length_x >= 0.0; }
     bool HasFocalLengthY() const { return focal_length_y >= 0.0; }
@@ -63,9 +63,9 @@
     double aspect_ratio = -1.0;
     WebString device_id;
     FacingMode facing_mode = FacingMode::kNone;
-    // |echo_cancellation| should be some form of Optional<bool> instead of int,
-    // but none is available for this file. Using -1 to indicate no value.
-    int echo_cancellation = -1;
+    base::Optional<bool> echo_cancellation;
+    base::Optional<bool> auto_gain_control;
+    base::Optional<bool> noise_supression;
     // Media Capture Depth Stream Extensions.
     WebString video_kind;
     double focal_length_x = -1.0;
diff --git a/third_party/WebKit/public/platform/modules/background_fetch/background_fetch.mojom b/third_party/WebKit/public/platform/modules/background_fetch/background_fetch.mojom
index 219d118..9af930b 100644
--- a/third_party/WebKit/public/platform/modules/background_fetch/background_fetch.mojom
+++ b/third_party/WebKit/public/platform/modules/background_fetch/background_fetch.mojom
@@ -6,6 +6,7 @@
 
 import "skia/public/interfaces/bitmap.mojom";
 import "third_party/WebKit/public/platform/modules/fetch/fetch_api_request.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
 
 enum BackgroundFetchError {
   NONE,
@@ -99,6 +100,10 @@
       => (BackgroundFetchError error,
           array<string> developer_ids);
 
+  // Gets size of the icon to display with the Background Fetch UI.
+  GetIconDisplaySize()
+    => (gfx.mojom.Size icon_size_pixels);
+
   // Registers the |observer| to receive events for the given registration
   // that is identified by the |unique_id|.
   AddRegistrationObserver(string unique_id,
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index f7d1344..c7ef258 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -66,6 +66,8 @@
     kV8CacheOptionsDefault,
     kV8CacheOptionsNone,
     kV8CacheOptionsCode,
+    kV8CacheOptionsCodeWithoutHeatCheck,
+    kV8CacheOptionsFullCodeWithoutHeatCheck
   };
 
   enum class SavePreviousDocumentResources {
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index b955c4d..72218d5 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -27,7 +27,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '327688'
+CLANG_REVISION = '328575'
 
 use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0')
                          in ('1', 'YES'))
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index be302c4..d6e9119 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -13333,6 +13333,14 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="OpenActiveTabInPwaWindow">
+  <owner>alancutter@chromium.org</owner>
+  <description>
+    Opens the current tab as an app window belonging to the PWA that has the URL
+    in its scope.
+  </description>
+</action>
+
 <action name="OpenAddBluetoothDeviceDialog">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5074fd5..a8b7857 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2738,6 +2738,8 @@
 <enum name="BackingStoreResults">
   <int value="0" label="Success"/>
   <int value="1" label="Failure"/>
+  <int value="2"
+      label="Mixed. Some steps failed, but transaction committed successfully"/>
 </enum>
 
 <enum name="BadMessageReasonChrome">
@@ -7168,6 +7170,13 @@
   <int value="1" label="Tap not suppressed"/>
 </enum>
 
+<enum name="CookieCommitProblem">
+  <int value="0" label="Entry encryption failed"/>
+  <int value="1" label="Adding cookie to DB failed."/>
+  <int value="2" label="Updating access time of cookie failed."/>
+  <int value="3" label="Deleting cookie failed."/>
+</enum>
+
 <enum name="CookieDeleteEquivalent">
   <int value="0"
       label="Attempt to delete an equivalent cookie during a set cookie
@@ -9952,10 +9961,18 @@
 </enum>
 
 <enum name="DownloadFileResult">
-  <int value="0" label="Completed"/>
-  <int value="1" label="Canceled"/>
-  <int value="2" label="Failure"/>
-  <int value="3" label="Other"/>
+  <int value="0" label="Completed">Download has successfully completed.</int>
+  <int value="1" label="Canceled">
+    In progress download was cancelled by the user.
+  </int>
+  <int value="2" label="Failure">Download has completed with error.</int>
+  <int value="3" label="Other">
+    In progress download did no finish because the tab was closed or user has
+    quit the app.
+  </int>
+  <int value="4" label="Not Started">
+    The user closed Download Manager UI without starting the download.
+  </int>
 </enum>
 
 <enum name="DownloadFunctions">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5992cef..9b40c8a9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12279,6 +12279,14 @@
   <summary>Intervals between access time updates for each cookie.</summary>
 </histogram>
 
+<histogram name="Cookie.CommitProblem" enum="CookieCommitProblem">
+  <owner>morlovich@chromium.org</owner>
+  <summary>
+    Recorded when a problem occurs trying to commit changes to the cookie store
+    back to disk, in the SQLite store.
+  </summary>
+</histogram>
+
 <histogram name="Cookie.CookieDeleteEquivalent" enum="CookieDeleteEquivalent">
   <owner>mkwst@chromium.org</owner>
   <summary>
@@ -87680,11 +87688,11 @@
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
-    Android: The time from the earliest entry point in the browser process to
-    the first contentful paint of the first loaded page. It's not recorded when
-    the first loaded page is non http(s) page like a chrome error page, a new
-    tab page, a blank page. It's also not recorded if the application wasn't in
-    the foreground since the start till the end of event.
+    Android: The time from the activity creation point to the first contentful
+    paint of the first loaded page. It's not recorded when the first loaded page
+    is non http(s) page like a chrome error page, a new tab page, a blank page.
+    It's also not recorded if the application wasn't in the foreground since the
+    start till the end of event.
   </summary>
 </histogram>
 
@@ -87693,12 +87701,12 @@
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
-    Android: The time from the earliest entry point in the browser process to
-    the moment the first navigation is committed, i.e. when renderer gets the
-    first byte of the document. It's not recorded when the first loaded page is
-    non http(s) page like a chrome error page, a new tab page, a blank page.
-    It's also not recorded if the application wasn't in the foreground since the
-    start till the end of event.
+    Android: The time from the activity creation point to the moment the first
+    navigation is committed, i.e. when renderer gets the first byte of the
+    document. It's not recorded when the first loaded page is non http(s) page
+    like a chrome error page, a new tab page, a blank page. It's also not
+    recorded if the application wasn't in the foreground since the start till
+    the end of event.
   </summary>
 </histogram>
 
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 36c99d6..266943b 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -1094,6 +1094,21 @@
           'build215-a9', 'build216-a9', 'build217-a9', 'build218-a9',
           'build219-a9', 'build220-a9'
       ],
+    },
+    'Android Go': {
+      'isolate': 'performance_test_suite',
+      'platform': 'android',
+      'dimension': {
+        'pool': 'chrome.tests.perf-fyi',
+        'os': 'Android',
+      },
+      'device_ids': [
+          'build30-a7--device1', 'build30-a7--device2', 'build30-a7--device3',
+          'build30-a7--device4', 'build30-a7--device5', 'build30-a7--device6',
+          'build30-a7--device7', 'build31-a7--device1', 'build31-a7--device2',
+          'build31-a7--device3', 'build31-a7--device4', 'build31-a7--device5',
+          'build31-a7--device6', 'build31-a7--device7'
+      ],
     }
   }
 }
@@ -1141,7 +1156,6 @@
 
   test_args = [
     '-v',
-    '--xvfb',
     '--browser=%s' % browser_name
   ]
 
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index b1aed81..51950f7a 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -427,7 +427,7 @@
     revision = int(data['point_id'])
 
   # For other revision data, add it if it's present and not undefined:
-  for key in ['webrtc_rev', 'v8_rev']:
+  for key in ['webrtc_git', 'v8_rev']:
     if key in data and data[key] != 'undefined':
       revision_supplemental_columns[prefix + key] = data[key]
 
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py
index c844bca..8ca49eb6 100755
--- a/tools/perf/core/upload_results_to_perf_dashboard.py
+++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -165,7 +165,7 @@
 
   versions = {}
   versions['rev'] = main_revision
-  versions['webrtc_rev'] = got_webrtc_revision
+  versions['webrtc_git'] = got_webrtc_revision
   versions['v8_rev'] = got_v8_revision
   versions['ver'] = version
   versions['git_revision'] = git_revision
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index acdf142..5520d136 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -354,7 +354,7 @@
 [ Android_Webview ] v8.browsing_mobile/browse:chrome:omnibox [ Skip ]
 [ Android_Webview ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
 crbug.com/815175 [ Nexus_5 ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
-crbug.com/714650 [ Nexus_5 ] v8.browsing_mobile/browse:news:cnn [ Skip ]
+crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
 
 # Benchmark: v8.browsing_mobile-future
@@ -373,11 +373,8 @@
 [ Android_Webview ] v8.browsing_mobile-future/browse:chrome:omnibox [ Skip ]
 [ Android_Webview ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
 crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
-crbug.com/799080 [ Nexus_5 ] v8.browsing_mobile-future/browse:social:tumblr_infinite_scroll [ Skip ]
 crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
-crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ]
-crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ]
 
 # Benchmark: v8.detached_context_age_in_gc
 crbug.com/770982 [ Win ] v8.detached_context_age_in_gc/Docs_(1_open_document_tab) [ Skip ]
diff --git a/ui/gfx/break_list.h b/ui/gfx/break_list.h
index 97d23c5..cb3de2b7 100644
--- a/ui/gfx/break_list.h
+++ b/ui/gfx/break_list.h
@@ -89,7 +89,7 @@
     return;
   DCHECK(!breaks_.empty());
   DCHECK(!range.is_reversed());
-  DCHECK(Range(0, max_).Contains(range));
+  DCHECK(Range(0, static_cast<uint32_t>(max_)).Contains(range));
 
   // Erase any breaks in |range|, then add start and end breaks as needed.
   typename std::vector<Break>::iterator start = GetBreak(range.start());
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index 025b1f0..311cc83 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -169,6 +169,14 @@
   node_data->SetName(accessible_name_);
 }
 
+bool MessageView::OnMousePressed(const ui::MouseEvent& event) {
+  return true;
+}
+
+bool MessageView::OnMouseDragged(const ui::MouseEvent& event) {
+  return true;
+}
+
 void MessageView::OnMouseReleased(const ui::MouseEvent& event) {
   if (!event.IsOnlyLeftMouseButton())
     return;
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h
index 7f9f9da9..3419947 100644
--- a/ui/message_center/views/message_view.h
+++ b/ui/message_center/views/message_view.h
@@ -81,6 +81,8 @@
 
   // views::View
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  bool OnMouseDragged(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   bool OnKeyReleased(const ui::KeyEvent& event) override;
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.mm b/ui/views/cocoa/native_widget_mac_nswindow.mm
index a61d582b..9a8ae3b 100644
--- a/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ b/ui/views/cocoa/native_widget_mac_nswindow.mm
@@ -139,7 +139,6 @@
                         object:self];
 
       [self performWindowDragWithEvent:event];
-      return;
     }
   }